Compare commits
35 Commits
yiming-250
...
05ef2e28f3
| Author | SHA1 | Date | |
|---|---|---|---|
| 05ef2e28f3 | |||
| 90ef949ca4 | |||
| 39c9dd29e1 | |||
| a6aa35176c | |||
| 6a43883d08 | |||
| 7d36d6b0a6 | |||
| 87a2c35300 | |||
| 7d57e292fe | |||
| 6fc82510cc | |||
| 4a36ce9c1c | |||
| 63cab37c87 | |||
| cd1e5c2cd0 | |||
| d7b0f29296 | |||
| 79854a2618 | |||
| 93aaffd3d8 | |||
| 71490b1fac | |||
| c6bd763485 | |||
| ad06b77fae | |||
| af5b1f71fb | |||
| 104f95eaec | |||
| c38dc55dff | |||
| 40da17b414 | |||
| f1e3f555e6 | |||
| 72db7ca928 | |||
| ebad44be71 | |||
| 68f2733530 | |||
| d752a01cc7 | |||
| 03e366c34a | |||
| d4748e415a | |||
| 42e46b4d35 | |||
| 69b9b1bbd1 | |||
| 4419dfff64 | |||
| 636b22849c | |||
| 0b0ddc82bd | |||
| ded24a8446 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,4 +4,5 @@
|
|||||||
packages
|
packages
|
||||||
obj/
|
obj/
|
||||||
*.user
|
*.user
|
||||||
*.log
|
*.log
|
||||||
|
**website.publishproj
|
||||||
Binary file not shown.
BIN
data/SQL/guadan_item_insert_script.sql
Normal file
BIN
data/SQL/guadan_item_insert_script.sql
Normal file
Binary file not shown.
Binary file not shown.
BIN
data/SQL/guadan_script_only_data.sql
Normal file
BIN
data/SQL/guadan_script_only_data.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
|
||||||
|
```
|
||||||
BIN
data/查詢範例.xlsx
Normal file
BIN
data/查詢範例.xlsx
Normal file
Binary file not shown.
33
web/App_Code/GuaDanStatusCode.cs
Normal file
33
web/App_Code/GuaDanStatusCode.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GuaDanStatusCode 的摘要描述
|
||||||
|
/// </summary>
|
||||||
|
public static class GuaDanStatusCode
|
||||||
|
{
|
||||||
|
public static class Bed
|
||||||
|
{
|
||||||
|
public const string Empty = "101"; // 空床:床位可分配
|
||||||
|
public const string Occupied = "102"; // 占用中:床位已有人使用
|
||||||
|
public const string Repair = "103"; // 維修停用:床位維修或不可使用
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Room
|
||||||
|
{
|
||||||
|
public const string Empty = "301"; // 空房:房間所有床位皆為空
|
||||||
|
public const string Partly = "302"; // 部分入住:房間有人,但仍有空床
|
||||||
|
public const string Full = "303"; // 已滿:房間所有床位皆已入住
|
||||||
|
public const string Repair = "304"; // 維修停用:房間維修或不可使用
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Guadan
|
||||||
|
{
|
||||||
|
public const string Booked = "401"; // 預訂成功:默認就是預訂成功狀態
|
||||||
|
public const string CheckedIn = "402"; // 已入住:已辦理入住
|
||||||
|
public const string CheckedOut = "403"; // 已退房
|
||||||
|
public const string Cancelled = "404"; // 已取消:取消後的狀態,不是取消的動作
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated from a template.
|
// 這個程式碼是由範本產生。
|
||||||
//
|
//
|
||||||
// Manual changes to this file may cause unexpected behavior in your application.
|
// 對這個檔案進行手動變更可能導致您的應用程式產生未預期的行為。
|
||||||
// Manual changes to this file will be overwritten if the code is regenerated.
|
// 如果重新產生程式碼,將會覆寫對這個檔案的手動變更。
|
||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -74,7 +74,6 @@ namespace Model
|
|||||||
public virtual DbSet<stock_reason> stock_reason { get; set; }
|
public virtual DbSet<stock_reason> stock_reason { get; set; }
|
||||||
public virtual DbSet<supplier> suppliers { get; set; }
|
public virtual DbSet<supplier> suppliers { get; set; }
|
||||||
public virtual DbSet<supplier_kind> supplier_kind { get; set; }
|
public virtual DbSet<supplier_kind> supplier_kind { get; set; }
|
||||||
public virtual DbSet<sysdiagram> sysdiagrams { get; set; }
|
|
||||||
public virtual DbSet<act_bom> act_bom { get; set; }
|
public virtual DbSet<act_bom> act_bom { get; set; }
|
||||||
public virtual DbSet<family_members> family_members { get; set; }
|
public virtual DbSet<family_members> family_members { get; set; }
|
||||||
public virtual DbSet<PostCity> PostCitiy { get; set; }
|
public virtual DbSet<PostCity> PostCitiy { get; set; }
|
||||||
|
|||||||
18
web/App_Code/Model/Model.Designer.cs
generated
18
web/App_Code/Model/Model.Designer.cs
generated
@@ -1,10 +1,10 @@
|
|||||||
// T4 code generation is enabled for model 'D:\dev\ez\17168erp\git_17888\web\App_Code\Model\Model.edmx'.
|
// 已啟用模型 'D:\17168erp_new_git\17168ERP\web\App_Code\Model\Model.edmx' 的 T4 程式碼產生。
|
||||||
// To enable legacy code generation, change the value of the 'Code Generation Strategy' designer
|
// 若要啟用舊版程式碼產生,請將 [程式碼產生策略] 設計工具屬性的值
|
||||||
// property to 'Legacy ObjectContext'. This property is available in the Properties Window when the model
|
//變更為 [舊版 ObjectContext]。當模型在設計工具中開啟時,這個屬性便可
|
||||||
// is open in the designer.
|
//以在 [屬性] 視窗中使用。
|
||||||
|
|
||||||
// If no context and entity classes have been generated, it may be because you created an empty model but
|
// 如果尚未產生任何內容和實體類型,可能是因為您建立了空的模型,但
|
||||||
// have not yet chosen which version of Entity Framework to use. To generate a context class and entity
|
//尚未選擇要使用的 Entity Framework 版本。若要為您的模型產生內容類別和
|
||||||
// classes for your model, open the model in the designer, right-click on the designer surface, and
|
//實體類型,請在設計工具中開啟模型,以滑鼠右鍵按一下設計工具介面並
|
||||||
// select 'Update Model from Database...', 'Generate Database from Model...', or 'Add Code Generation
|
//選取 [從資料庫更新模型]、[由模型產生資料庫] 或 [加入程式碼產生
|
||||||
// Item...'.
|
//項目]。
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated from a template.
|
// 這個程式碼是由範本產生。
|
||||||
//
|
//
|
||||||
// Manual changes to this file may cause unexpected behavior in your application.
|
// 對這個檔案進行手動變更可能導致您的應用程式產生未預期的行為。
|
||||||
// Manual changes to this file will be overwritten if the code is regenerated.
|
// 如果重新產生程式碼,將會覆寫對這個檔案的手動變更。
|
||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -441,7 +441,7 @@ namespace Model
|
|||||||
{
|
{
|
||||||
this.members = new HashSet<member>();
|
this.members = new HashSet<member>();
|
||||||
this.news = new HashSet<news>();
|
this.news = new HashSet<news>();
|
||||||
this.GuaDanOrders = new HashSet<GuaDanOrder>();
|
this.GuaDanOrder = new HashSet<GuaDanOrder>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int num { get; set; }
|
public int num { get; set; }
|
||||||
@@ -477,7 +477,7 @@ namespace Model
|
|||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<news> news { get; set; }
|
public virtual ICollection<news> news { get; set; }
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<GuaDanOrder> GuaDanOrders { get; set; }
|
public virtual ICollection<GuaDanOrder> GuaDanOrder { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace Model
|
namespace Model
|
||||||
@@ -768,8 +768,8 @@ namespace Model
|
|||||||
this.family_members = new HashSet<family_members>();
|
this.family_members = new HashSet<family_members>();
|
||||||
this.transfer_register = new HashSet<transfer_register>();
|
this.transfer_register = new HashSet<transfer_register>();
|
||||||
this.transfer_register1 = new HashSet<transfer_register>();
|
this.transfer_register1 = new HashSet<transfer_register>();
|
||||||
this.GuaDanOrders = new HashSet<GuaDanOrder>();
|
this.GuaDanOrder = new HashSet<GuaDanOrder>();
|
||||||
this.GuaDanOrderGuests = new HashSet<GuaDanOrderGuest>();
|
this.GuaDanOrderGuest = new HashSet<GuaDanOrderGuest>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int num { get; set; }
|
public int num { get; set; }
|
||||||
@@ -830,9 +830,9 @@ namespace Model
|
|||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<transfer_register> transfer_register1 { get; set; }
|
public virtual ICollection<transfer_register> transfer_register1 { get; set; }
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<GuaDanOrder> GuaDanOrders { get; set; }
|
public virtual ICollection<GuaDanOrder> GuaDanOrder { get; set; }
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuests { get; set; }
|
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuest { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace Model
|
namespace Model
|
||||||
@@ -869,9 +869,11 @@ namespace Model
|
|||||||
public string BookerPhone { get; set; }
|
public string BookerPhone { get; set; }
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
public System.Guid Uuid { get; set; }
|
public System.Guid Uuid { get; set; }
|
||||||
|
public Nullable<int> ActivityNum { get; set; }
|
||||||
|
public bool IsCancel { get; set; }
|
||||||
|
|
||||||
public virtual admin admin { get; set; }
|
public virtual admin admin { get; set; }
|
||||||
public virtual follower follower { get; set; }
|
public virtual follower followers { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace Model
|
namespace Model
|
||||||
@@ -881,6 +883,12 @@ namespace Model
|
|||||||
|
|
||||||
public partial class GuaDanOrderGuest
|
public partial class GuaDanOrderGuest
|
||||||
{
|
{
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||||
|
public GuaDanOrderGuest()
|
||||||
|
{
|
||||||
|
this.RegionAndRoomAndBedSchedule = new HashSet<RegionAndRoomAndBedSchedule>();
|
||||||
|
}
|
||||||
|
|
||||||
public string GuaDanOrderNo { get; set; }
|
public string GuaDanOrderNo { get; set; }
|
||||||
public Nullable<int> FollowerNum { get; set; }
|
public Nullable<int> FollowerNum { get; set; }
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
@@ -889,12 +897,14 @@ namespace Model
|
|||||||
public Nullable<System.Guid> BedUuid { get; set; }
|
public Nullable<System.Guid> BedUuid { get; set; }
|
||||||
public Nullable<System.DateTime> CheckInAt { get; set; }
|
public Nullable<System.DateTime> CheckInAt { get; set; }
|
||||||
public Nullable<System.DateTime> CheckOutAt { get; set; }
|
public Nullable<System.DateTime> CheckOutAt { get; set; }
|
||||||
public Nullable<System.Guid> statusUuid { get; set; }
|
public string StatusCode { get; set; }
|
||||||
|
|
||||||
public virtual follower follower { get; set; }
|
public virtual follower followers { get; set; }
|
||||||
public virtual RegionRoomBed RegionRoomBed { get; set; }
|
public virtual RegionRoomBed RegionRoomBed { get; set; }
|
||||||
public virtual Room Room { get; set; }
|
public virtual Room Room { get; set; }
|
||||||
public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; }
|
public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; }
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
|
public virtual ICollection<RegionAndRoomAndBedSchedule> RegionAndRoomAndBedSchedule { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace Model
|
namespace Model
|
||||||
@@ -1393,7 +1403,10 @@ namespace Model
|
|||||||
public Nullable<System.Guid> TargetUuid { get; set; }
|
public Nullable<System.Guid> TargetUuid { get; set; }
|
||||||
public string GuaDanOrderNo { get; set; }
|
public string GuaDanOrderNo { get; set; }
|
||||||
public Nullable<System.DateTime> ScheduleDate { get; set; }
|
public Nullable<System.DateTime> ScheduleDate { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsCancel { get; set; }
|
||||||
|
public Nullable<System.Guid> GuaDanOrderGuestUuid { get; set; }
|
||||||
|
|
||||||
|
public virtual GuaDanOrderGuest GuaDanOrderGuest { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace Model
|
namespace Model
|
||||||
@@ -1406,7 +1419,7 @@ namespace Model
|
|||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||||
public RegionRoomBed()
|
public RegionRoomBed()
|
||||||
{
|
{
|
||||||
this.GuaDanOrderGuests = new HashSet<GuaDanOrderGuest>();
|
this.GuaDanOrderGuest = new HashSet<GuaDanOrderGuest>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
@@ -1415,12 +1428,12 @@ namespace Model
|
|||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
public System.Guid Uuid { get; set; }
|
public System.Guid Uuid { get; set; }
|
||||||
public System.Guid RoomUuid { get; set; }
|
public System.Guid RoomUuid { get; set; }
|
||||||
public Nullable<System.Guid> StatusUuid { get; set; }
|
public string StatusCode { get; set; }
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuests { get; set; }
|
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuest { get; set; }
|
||||||
public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; }
|
|
||||||
public virtual Room Room { get; set; }
|
public virtual Room Room { get; set; }
|
||||||
|
public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace Model
|
namespace Model
|
||||||
@@ -1433,8 +1446,8 @@ namespace Model
|
|||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||||
public RegionRoomBedStatus()
|
public RegionRoomBedStatus()
|
||||||
{
|
{
|
||||||
this.GuaDanOrderGuests = new HashSet<GuaDanOrderGuest>();
|
this.GuaDanOrderGuest = new HashSet<GuaDanOrderGuest>();
|
||||||
this.RegionRoomBeds = new HashSet<RegionRoomBed>();
|
this.RegionRoomBed = new HashSet<RegionRoomBed>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Code { get; set; }
|
public string Code { get; set; }
|
||||||
@@ -1442,12 +1455,11 @@ namespace Model
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public Nullable<int> Category { get; set; }
|
public Nullable<int> Category { get; set; }
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
public System.Guid Uuid { get; set; }
|
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuests { get; set; }
|
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuest { get; set; }
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<RegionRoomBed> RegionRoomBeds { get; set; }
|
public virtual ICollection<RegionRoomBed> RegionRoomBed { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace Model
|
namespace Model
|
||||||
@@ -1460,7 +1472,7 @@ namespace Model
|
|||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||||
public RegionType()
|
public RegionType()
|
||||||
{
|
{
|
||||||
this.Regions = new HashSet<Region>();
|
this.Region = new HashSet<Region>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Code { get; set; }
|
public string Code { get; set; }
|
||||||
@@ -1471,7 +1483,7 @@ namespace Model
|
|||||||
public System.Guid Uuid { get; set; }
|
public System.Guid Uuid { get; set; }
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<Region> Regions { get; set; }
|
public virtual ICollection<Region> Region { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace Model
|
namespace Model
|
||||||
@@ -1484,7 +1496,7 @@ namespace Model
|
|||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||||
public Room()
|
public Room()
|
||||||
{
|
{
|
||||||
this.GuaDanOrderGuests = new HashSet<GuaDanOrderGuest>();
|
this.GuaDanOrderGuest = new HashSet<GuaDanOrderGuest>();
|
||||||
this.RegionRoomBed = new HashSet<RegionRoomBed>();
|
this.RegionRoomBed = new HashSet<RegionRoomBed>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1499,7 +1511,7 @@ namespace Model
|
|||||||
public System.Guid RegionUuid { get; set; }
|
public System.Guid RegionUuid { get; set; }
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuests { get; set; }
|
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuest { get; set; }
|
||||||
public virtual Region Region { get; set; }
|
public virtual Region Region { get; set; }
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||||
public virtual ICollection<RegionRoomBed> RegionRoomBed { get; set; }
|
public virtual ICollection<RegionRoomBed> RegionRoomBed { get; set; }
|
||||||
@@ -1685,20 +1697,6 @@ namespace Model
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public partial class sysdiagram
|
|
||||||
{
|
|
||||||
public string name { get; set; }
|
|
||||||
public int principal_id { get; set; }
|
|
||||||
public int diagram_id { get; set; }
|
|
||||||
public Nullable<int> version { get; set; }
|
|
||||||
public byte[] definition { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
namespace Model
|
|
||||||
{
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
public partial class transfer_register
|
public partial class transfer_register
|
||||||
{
|
{
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||||
|
|||||||
@@ -438,6 +438,8 @@
|
|||||||
<Property Name="BookerPhone" Type="nvarchar" MaxLength="12" />
|
<Property Name="BookerPhone" Type="nvarchar" MaxLength="12" />
|
||||||
<Property Name="IsDeleted" Type="bit" Nullable="false" />
|
<Property Name="IsDeleted" Type="bit" Nullable="false" />
|
||||||
<Property Name="Uuid" Type="uniqueidentifier" Nullable="false" />
|
<Property Name="Uuid" Type="uniqueidentifier" Nullable="false" />
|
||||||
|
<Property Name="ActivityNum" Type="int" />
|
||||||
|
<Property Name="IsCancel" Type="bit" Nullable="false" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="GuaDanOrderGuest">
|
<EntityType Name="GuaDanOrderGuest">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -451,7 +453,7 @@
|
|||||||
<Property Name="BedUuid" Type="uniqueidentifier" />
|
<Property Name="BedUuid" Type="uniqueidentifier" />
|
||||||
<Property Name="CheckInAt" Type="date" />
|
<Property Name="CheckInAt" Type="date" />
|
||||||
<Property Name="CheckOutAt" Type="date" />
|
<Property Name="CheckOutAt" Type="date" />
|
||||||
<Property Name="statusUuid" Type="uniqueidentifier" />
|
<Property Name="StatusCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="GuadanTimeSetting">
|
<EntityType Name="GuadanTimeSetting">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -733,7 +735,8 @@
|
|||||||
<Property Name="TargetUuid" Type="uniqueidentifier" />
|
<Property Name="TargetUuid" Type="uniqueidentifier" />
|
||||||
<Property Name="GuaDanOrderNo" Type="nvarchar" MaxLength="20" />
|
<Property Name="GuaDanOrderNo" Type="nvarchar" MaxLength="20" />
|
||||||
<Property Name="ScheduleDate" Type="date" />
|
<Property Name="ScheduleDate" Type="date" />
|
||||||
<Property Name="IsActive" Type="bit" Nullable="false" />
|
<Property Name="IsCancel" Type="bit" Nullable="false" />
|
||||||
|
<Property Name="GuaDanOrderGuestUuid" Type="uniqueidentifier" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="RegionRoomBed">
|
<EntityType Name="RegionRoomBed">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -745,18 +748,17 @@
|
|||||||
<Property Name="IsDeleted" Type="bit" Nullable="false" />
|
<Property Name="IsDeleted" Type="bit" Nullable="false" />
|
||||||
<Property Name="Uuid" Type="uniqueidentifier" Nullable="false" />
|
<Property Name="Uuid" Type="uniqueidentifier" Nullable="false" />
|
||||||
<Property Name="RoomUuid" Type="uniqueidentifier" Nullable="false" />
|
<Property Name="RoomUuid" Type="uniqueidentifier" Nullable="false" />
|
||||||
<Property Name="StatusUuid" Type="uniqueidentifier" />
|
<Property Name="StatusCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="RegionRoomBedStatus">
|
<EntityType Name="RegionRoomBedStatus">
|
||||||
<Key>
|
<Key>
|
||||||
<PropertyRef Name="Uuid" />
|
<PropertyRef Name="Code" />
|
||||||
</Key>
|
</Key>
|
||||||
<Property Name="Code" Type="nvarchar" MaxLength="20" />
|
<Property Name="Code" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||||
<Property Name="Name" Type="nvarchar" MaxLength="50" Nullable="false" />
|
<Property Name="Name" Type="nvarchar" MaxLength="50" Nullable="false" />
|
||||||
<Property Name="Description" Type="nvarchar" MaxLength="50" />
|
<Property Name="Description" Type="nvarchar" MaxLength="50" />
|
||||||
<Property Name="Category" Type="int" />
|
<Property Name="Category" Type="int" />
|
||||||
<Property Name="IsDeleted" Type="bit" Nullable="false" />
|
<Property Name="IsDeleted" Type="bit" Nullable="false" />
|
||||||
<Property Name="Uuid" Type="uniqueidentifier" Nullable="false" />
|
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="RegionType">
|
<EntityType Name="RegionType">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -876,16 +878,6 @@
|
|||||||
<Property Name="range" Type="int" />
|
<Property Name="range" Type="int" />
|
||||||
<Property Name="demo" Type="nvarchar(max)" />
|
<Property Name="demo" Type="nvarchar(max)" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="sysdiagrams">
|
|
||||||
<Key>
|
|
||||||
<PropertyRef Name="diagram_id" />
|
|
||||||
</Key>
|
|
||||||
<Property Name="name" Type="nvarchar" MaxLength="128" Nullable="false" />
|
|
||||||
<Property Name="principal_id" Type="int" Nullable="false" />
|
|
||||||
<Property Name="diagram_id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
|
|
||||||
<Property Name="version" Type="int" />
|
|
||||||
<Property Name="definition" Type="varbinary(max)" />
|
|
||||||
</EntityType>
|
|
||||||
<EntityType Name="transfer_register">
|
<EntityType Name="transfer_register">
|
||||||
<Key>
|
<Key>
|
||||||
<PropertyRef Name="id" />
|
<PropertyRef Name="id" />
|
||||||
@@ -1392,15 +1384,15 @@
|
|||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
<Association Name="FK_GuaDanOrderGuest_Status">
|
<Association Name="FK_GuaDanOrderGuest_StatusCode">
|
||||||
<End Role="RegionRoomBedStatus" Type="Self.RegionRoomBedStatus" Multiplicity="0..1" />
|
<End Role="RegionRoomBedStatus" Type="Self.RegionRoomBedStatus" Multiplicity="1" />
|
||||||
<End Role="GuaDanOrderGuest" Type="Self.GuaDanOrderGuest" Multiplicity="*" />
|
<End Role="GuaDanOrderGuest" Type="Self.GuaDanOrderGuest" Multiplicity="*" />
|
||||||
<ReferentialConstraint>
|
<ReferentialConstraint>
|
||||||
<Principal Role="RegionRoomBedStatus">
|
<Principal Role="RegionRoomBedStatus">
|
||||||
<PropertyRef Name="Uuid" />
|
<PropertyRef Name="Code" />
|
||||||
</Principal>
|
</Principal>
|
||||||
<Dependent Role="GuaDanOrderGuest">
|
<Dependent Role="GuaDanOrderGuest">
|
||||||
<PropertyRef Name="statusUuid" />
|
<PropertyRef Name="StatusCode" />
|
||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
@@ -1702,18 +1694,6 @@
|
|||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
<Association Name="FK_RegionRoomBed_RegionRoomBedStatus">
|
|
||||||
<End Role="RegionRoomBedStatus" Type="Self.RegionRoomBedStatus" Multiplicity="0..1" />
|
|
||||||
<End Role="RegionRoomBed" Type="Self.RegionRoomBed" Multiplicity="*" />
|
|
||||||
<ReferentialConstraint>
|
|
||||||
<Principal Role="RegionRoomBedStatus">
|
|
||||||
<PropertyRef Name="Uuid" />
|
|
||||||
</Principal>
|
|
||||||
<Dependent Role="RegionRoomBed">
|
|
||||||
<PropertyRef Name="StatusUuid" />
|
|
||||||
</Dependent>
|
|
||||||
</ReferentialConstraint>
|
|
||||||
</Association>
|
|
||||||
<Association Name="FK_RegionRoomBed_RoomUuid">
|
<Association Name="FK_RegionRoomBed_RoomUuid">
|
||||||
<End Role="Room" Type="Self.Room" Multiplicity="1" />
|
<End Role="Room" Type="Self.Room" Multiplicity="1" />
|
||||||
<End Role="RegionRoomBed" Type="Self.RegionRoomBed" Multiplicity="*" />
|
<End Role="RegionRoomBed" Type="Self.RegionRoomBed" Multiplicity="*" />
|
||||||
@@ -1726,6 +1706,18 @@
|
|||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
|
<Association Name="FK_RegionRoomBed_StatusCode">
|
||||||
|
<End Role="RegionRoomBedStatus" Type="Self.RegionRoomBedStatus" Multiplicity="1" />
|
||||||
|
<End Role="RegionRoomBed" Type="Self.RegionRoomBed" Multiplicity="*" />
|
||||||
|
<ReferentialConstraint>
|
||||||
|
<Principal Role="RegionRoomBedStatus">
|
||||||
|
<PropertyRef Name="Code" />
|
||||||
|
</Principal>
|
||||||
|
<Dependent Role="RegionRoomBed">
|
||||||
|
<PropertyRef Name="StatusCode" />
|
||||||
|
</Dependent>
|
||||||
|
</ReferentialConstraint>
|
||||||
|
</Association>
|
||||||
<Association Name="FK_Room_Region">
|
<Association Name="FK_Room_Region">
|
||||||
<End Role="Region" Type="Self.Region" Multiplicity="1" />
|
<End Role="Region" Type="Self.Region" Multiplicity="1" />
|
||||||
<End Role="Room" Type="Self.Room" Multiplicity="*" />
|
<End Role="Room" Type="Self.Room" Multiplicity="*" />
|
||||||
@@ -1738,6 +1730,18 @@
|
|||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
|
<Association Name="FK_Schedule_GuaDanOrderGuest">
|
||||||
|
<End Role="GuaDanOrderGuest" Type="Self.GuaDanOrderGuest" Multiplicity="0..1" />
|
||||||
|
<End Role="RegionAndRoomAndBedSchedule" Type="Self.RegionAndRoomAndBedSchedule" Multiplicity="*" />
|
||||||
|
<ReferentialConstraint>
|
||||||
|
<Principal Role="GuaDanOrderGuest">
|
||||||
|
<PropertyRef Name="Uuid" />
|
||||||
|
</Principal>
|
||||||
|
<Dependent Role="RegionAndRoomAndBedSchedule">
|
||||||
|
<PropertyRef Name="GuaDanOrderGuestUuid" />
|
||||||
|
</Dependent>
|
||||||
|
</ReferentialConstraint>
|
||||||
|
</Association>
|
||||||
<Association Name="FK_stock_actItem">
|
<Association Name="FK_stock_actItem">
|
||||||
<End Role="actItem" Type="Self.actItem" Multiplicity="0..1">
|
<End Role="actItem" Type="Self.actItem" Multiplicity="0..1">
|
||||||
<OnDelete Action="Cascade" />
|
<OnDelete Action="Cascade" />
|
||||||
@@ -1934,7 +1938,6 @@
|
|||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
<Function Name="fn_diagramobjects" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo" ReturnType="int" />
|
|
||||||
<Function Name="pager_eztrust" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
|
<Function Name="pager_eztrust" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
|
||||||
<Parameter Name="StartRowIndex" Type="int" Mode="In" />
|
<Parameter Name="StartRowIndex" Type="int" Mode="In" />
|
||||||
<Parameter Name="PageSize" Type="int" Mode="In" />
|
<Parameter Name="PageSize" Type="int" Mode="In" />
|
||||||
@@ -1944,36 +1947,6 @@
|
|||||||
<Parameter Name="orderBy" Type="nvarchar" Mode="In" />
|
<Parameter Name="orderBy" Type="nvarchar" Mode="In" />
|
||||||
<Parameter Name="rowCount" Type="int" Mode="InOut" />
|
<Parameter Name="rowCount" Type="int" Mode="InOut" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function Name="sp_alterdiagram" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
|
|
||||||
<Parameter Name="diagramname" Type="nvarchar" Mode="In" />
|
|
||||||
<Parameter Name="owner_id" Type="int" Mode="In" />
|
|
||||||
<Parameter Name="version" Type="int" Mode="In" />
|
|
||||||
<Parameter Name="definition" Type="varbinary(max)" Mode="In" />
|
|
||||||
</Function>
|
|
||||||
<Function Name="sp_creatediagram" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
|
|
||||||
<Parameter Name="diagramname" Type="nvarchar" Mode="In" />
|
|
||||||
<Parameter Name="owner_id" Type="int" Mode="In" />
|
|
||||||
<Parameter Name="version" Type="int" Mode="In" />
|
|
||||||
<Parameter Name="definition" Type="varbinary(max)" Mode="In" />
|
|
||||||
</Function>
|
|
||||||
<Function Name="sp_dropdiagram" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
|
|
||||||
<Parameter Name="diagramname" Type="nvarchar" Mode="In" />
|
|
||||||
<Parameter Name="owner_id" Type="int" Mode="In" />
|
|
||||||
</Function>
|
|
||||||
<Function Name="sp_helpdiagramdefinition" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
|
|
||||||
<Parameter Name="diagramname" Type="nvarchar" Mode="In" />
|
|
||||||
<Parameter Name="owner_id" Type="int" Mode="In" />
|
|
||||||
</Function>
|
|
||||||
<Function Name="sp_helpdiagrams" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
|
|
||||||
<Parameter Name="diagramname" Type="nvarchar" Mode="In" />
|
|
||||||
<Parameter Name="owner_id" Type="int" Mode="In" />
|
|
||||||
</Function>
|
|
||||||
<Function Name="sp_renamediagram" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
|
|
||||||
<Parameter Name="diagramname" Type="nvarchar" Mode="In" />
|
|
||||||
<Parameter Name="owner_id" Type="int" Mode="In" />
|
|
||||||
<Parameter Name="new_diagramname" Type="nvarchar" Mode="In" />
|
|
||||||
</Function>
|
|
||||||
<Function Name="sp_upgraddiagrams" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo" />
|
|
||||||
<EntityContainer Name="ModelStoreContainer">
|
<EntityContainer Name="ModelStoreContainer">
|
||||||
<EntitySet Name="accounting" EntityType="Self.accounting" Schema="dbo" store:Type="Tables" />
|
<EntitySet Name="accounting" EntityType="Self.accounting" Schema="dbo" store:Type="Tables" />
|
||||||
<EntitySet Name="accounting_files" EntityType="Self.accounting_files" Schema="dbo" store:Type="Tables" />
|
<EntitySet Name="accounting_files" EntityType="Self.accounting_files" Schema="dbo" store:Type="Tables" />
|
||||||
@@ -2036,7 +2009,6 @@
|
|||||||
<EntitySet Name="stock_reason" EntityType="Self.stock_reason" Schema="dbo" store:Type="Tables" />
|
<EntitySet Name="stock_reason" EntityType="Self.stock_reason" Schema="dbo" store:Type="Tables" />
|
||||||
<EntitySet Name="supplier" EntityType="Self.supplier" Schema="dbo" store:Type="Tables" />
|
<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="supplier_kind" EntityType="Self.supplier_kind" Schema="dbo" store:Type="Tables" />
|
||||||
<EntitySet Name="sysdiagrams" EntityType="Self.sysdiagrams" Schema="dbo" store:Type="Tables" />
|
|
||||||
<EntitySet Name="transfer_register" EntityType="Self.transfer_register" Schema="dbo" store:Type="Tables" />
|
<EntitySet Name="transfer_register" EntityType="Self.transfer_register" Schema="dbo" store:Type="Tables" />
|
||||||
<AssociationSet Name="FK_accounting_accounting_kind" Association="Self.FK_accounting_accounting_kind">
|
<AssociationSet Name="FK_accounting_accounting_kind" Association="Self.FK_accounting_accounting_kind">
|
||||||
<End Role="accounting_kind" EntitySet="accounting_kind" />
|
<End Role="accounting_kind" EntitySet="accounting_kind" />
|
||||||
@@ -2190,7 +2162,7 @@
|
|||||||
<End Role="Room" EntitySet="Room" />
|
<End Role="Room" EntitySet="Room" />
|
||||||
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
<AssociationSet Name="FK_GuaDanOrderGuest_Status" Association="Self.FK_GuaDanOrderGuest_Status">
|
<AssociationSet Name="FK_GuaDanOrderGuest_StatusCode" Association="Self.FK_GuaDanOrderGuest_StatusCode">
|
||||||
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
||||||
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
@@ -2290,18 +2262,22 @@
|
|||||||
<End Role="RegionType" EntitySet="RegionType" />
|
<End Role="RegionType" EntitySet="RegionType" />
|
||||||
<End Role="Region" EntitySet="Region" />
|
<End Role="Region" EntitySet="Region" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
<AssociationSet Name="FK_RegionRoomBed_RegionRoomBedStatus" Association="Self.FK_RegionRoomBed_RegionRoomBedStatus">
|
|
||||||
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
|
||||||
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
|
||||||
</AssociationSet>
|
|
||||||
<AssociationSet Name="FK_RegionRoomBed_RoomUuid" Association="Self.FK_RegionRoomBed_RoomUuid">
|
<AssociationSet Name="FK_RegionRoomBed_RoomUuid" Association="Self.FK_RegionRoomBed_RoomUuid">
|
||||||
<End Role="Room" EntitySet="Room" />
|
<End Role="Room" EntitySet="Room" />
|
||||||
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
|
<AssociationSet Name="FK_RegionRoomBed_StatusCode" Association="Self.FK_RegionRoomBed_StatusCode">
|
||||||
|
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
||||||
|
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
||||||
|
</AssociationSet>
|
||||||
<AssociationSet Name="FK_Room_Region" Association="Self.FK_Room_Region">
|
<AssociationSet Name="FK_Room_Region" Association="Self.FK_Room_Region">
|
||||||
<End Role="Region" EntitySet="Region" />
|
<End Role="Region" EntitySet="Region" />
|
||||||
<End Role="Room" EntitySet="Room" />
|
<End Role="Room" EntitySet="Room" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
|
<AssociationSet Name="FK_Schedule_GuaDanOrderGuest" Association="Self.FK_Schedule_GuaDanOrderGuest">
|
||||||
|
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||||
|
<End Role="RegionAndRoomAndBedSchedule" EntitySet="RegionAndRoomAndBedSchedule" />
|
||||||
|
</AssociationSet>
|
||||||
<AssociationSet Name="FK_stock_actItem" Association="Self.FK_stock_actItem">
|
<AssociationSet Name="FK_stock_actItem" Association="Self.FK_stock_actItem">
|
||||||
<End Role="actItem" EntitySet="actItem" />
|
<End Role="actItem" EntitySet="actItem" />
|
||||||
<End Role="stock" EntitySet="stock" />
|
<End Role="stock" EntitySet="stock" />
|
||||||
@@ -2634,7 +2610,7 @@
|
|||||||
<NavigationProperty Name="admin_group" Relationship="Self.FK_admin_admin_group" FromRole="admin" ToRole="admin_group" />
|
<NavigationProperty Name="admin_group" Relationship="Self.FK_admin_admin_group" FromRole="admin" ToRole="admin_group" />
|
||||||
<NavigationProperty Name="members" Relationship="Self.FK_member_admin" FromRole="admin" ToRole="member" />
|
<NavigationProperty Name="members" Relationship="Self.FK_member_admin" FromRole="admin" ToRole="member" />
|
||||||
<NavigationProperty Name="news" Relationship="Self.FK_news_admin" FromRole="admin" ToRole="news" />
|
<NavigationProperty Name="news" Relationship="Self.FK_news_admin" FromRole="admin" ToRole="news" />
|
||||||
<NavigationProperty Name="GuaDanOrders" Relationship="Model.FK_GuaDanOrder_Admin_CreateUser" FromRole="admin" ToRole="GuaDanOrder" />
|
<NavigationProperty Name="GuaDanOrder" Relationship="Model.FK_GuaDanOrder_Admin_CreateUser" FromRole="admin" ToRole="GuaDanOrder" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="admin_group">
|
<EntityType Name="admin_group">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -2824,8 +2800,8 @@
|
|||||||
<NavigationProperty Name="family_members" Relationship="Model.FK_family_members_followers" FromRole="follower" ToRole="family_members" />
|
<NavigationProperty Name="family_members" Relationship="Model.FK_family_members_followers" FromRole="follower" ToRole="family_members" />
|
||||||
<NavigationProperty Name="transfer_register" Relationship="Model.FK_transfer_register_followers" FromRole="follower" ToRole="transfer_register" />
|
<NavigationProperty Name="transfer_register" Relationship="Model.FK_transfer_register_followers" FromRole="follower" ToRole="transfer_register" />
|
||||||
<NavigationProperty Name="transfer_register1" Relationship="Model.FK_transfer_register_followers_match" FromRole="follower" ToRole="transfer_register" />
|
<NavigationProperty Name="transfer_register1" Relationship="Model.FK_transfer_register_followers_match" FromRole="follower" ToRole="transfer_register" />
|
||||||
<NavigationProperty Name="GuaDanOrders" Relationship="Model.FK_GuaDanOrder_Followers" FromRole="follower" ToRole="GuaDanOrder" />
|
<NavigationProperty Name="GuaDanOrder" Relationship="Model.FK_GuaDanOrder_Followers" FromRole="follower" ToRole="GuaDanOrder" />
|
||||||
<NavigationProperty Name="GuaDanOrderGuests" Relationship="Model.FK_GuaDanOrderGuest_FOLLOWERS" FromRole="follower" ToRole="GuaDanOrderGuest" />
|
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_GuaDanOrderGuest_FOLLOWERS" FromRole="follower" ToRole="GuaDanOrderGuest" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="followers_tablet">
|
<EntityType Name="followers_tablet">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -3192,16 +3168,6 @@
|
|||||||
<Property Name="demo" Type="String" MaxLength="Max" FixedLength="false" Unicode="true" />
|
<Property Name="demo" Type="String" MaxLength="Max" FixedLength="false" Unicode="true" />
|
||||||
<NavigationProperty Name="suppliers" Relationship="Self.FK_supplier_supplier_kind" FromRole="supplier_kind" ToRole="supplier" />
|
<NavigationProperty Name="suppliers" Relationship="Self.FK_supplier_supplier_kind" FromRole="supplier_kind" ToRole="supplier" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="sysdiagram">
|
|
||||||
<Key>
|
|
||||||
<PropertyRef Name="diagram_id" />
|
|
||||||
</Key>
|
|
||||||
<Property Name="name" Type="String" MaxLength="128" FixedLength="false" Unicode="true" Nullable="false" />
|
|
||||||
<Property Name="principal_id" Type="Int32" Nullable="false" />
|
|
||||||
<Property Name="diagram_id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
|
|
||||||
<Property Name="version" Type="Int32" />
|
|
||||||
<Property Name="definition" Type="Binary" MaxLength="Max" FixedLength="false" />
|
|
||||||
</EntityType>
|
|
||||||
<Association Name="FK_accounting_accounting_kind">
|
<Association Name="FK_accounting_accounting_kind">
|
||||||
<End Role="accounting_kind" Type="Self.accounting_kind" Multiplicity="0..1" />
|
<End Role="accounting_kind" Type="Self.accounting_kind" Multiplicity="0..1" />
|
||||||
<End Role="accounting" Type="Self.accounting" Multiplicity="*" />
|
<End Role="accounting" Type="Self.accounting" Multiplicity="*" />
|
||||||
@@ -3992,7 +3958,6 @@
|
|||||||
<EntitySet Name="stock_reason" EntityType="Self.stock_reason" />
|
<EntitySet Name="stock_reason" EntityType="Self.stock_reason" />
|
||||||
<EntitySet Name="suppliers" EntityType="Self.supplier" />
|
<EntitySet Name="suppliers" EntityType="Self.supplier" />
|
||||||
<EntitySet Name="supplier_kind" EntityType="Self.supplier_kind" />
|
<EntitySet Name="supplier_kind" EntityType="Self.supplier_kind" />
|
||||||
<EntitySet Name="sysdiagrams" EntityType="Self.sysdiagram" />
|
|
||||||
<AssociationSet Name="FK_accounting_accounting_kind" Association="Self.FK_accounting_accounting_kind">
|
<AssociationSet Name="FK_accounting_accounting_kind" Association="Self.FK_accounting_accounting_kind">
|
||||||
<End Role="accounting_kind" EntitySet="accounting_kind" />
|
<End Role="accounting_kind" EntitySet="accounting_kind" />
|
||||||
<End Role="accounting" EntitySet="accountings" />
|
<End Role="accounting" EntitySet="accountings" />
|
||||||
@@ -4355,10 +4320,14 @@
|
|||||||
<End Role="Room" EntitySet="Room" />
|
<End Role="Room" EntitySet="Room" />
|
||||||
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
<AssociationSet Name="FK_GuaDanOrderGuest_Status" Association="Model.FK_GuaDanOrderGuest_Status">
|
<AssociationSet Name="FK_GuaDanOrderGuest_StatusCode" Association="Model.FK_GuaDanOrderGuest_StatusCode">
|
||||||
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
||||||
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
|
<AssociationSet Name="FK_Schedule_GuaDanOrderGuest" Association="Model.FK_Schedule_GuaDanOrderGuest">
|
||||||
|
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||||
|
<End Role="RegionAndRoomAndBedSchedule" EntitySet="RegionAndRoomAndBedSchedule" />
|
||||||
|
</AssociationSet>
|
||||||
<AssociationSet Name="FK_Region_ParentUuid" Association="Model.FK_Region_ParentUuid">
|
<AssociationSet Name="FK_Region_ParentUuid" Association="Model.FK_Region_ParentUuid">
|
||||||
<End Role="Region" EntitySet="Region" />
|
<End Role="Region" EntitySet="Region" />
|
||||||
<End Role="Region1" EntitySet="Region" />
|
<End Role="Region1" EntitySet="Region" />
|
||||||
@@ -4371,14 +4340,14 @@
|
|||||||
<End Role="Region" EntitySet="Region" />
|
<End Role="Region" EntitySet="Region" />
|
||||||
<End Role="Room" EntitySet="Room" />
|
<End Role="Room" EntitySet="Room" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
<AssociationSet Name="FK_RegionRoomBed_RegionRoomBedStatus" Association="Model.FK_RegionRoomBed_RegionRoomBedStatus">
|
|
||||||
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
|
||||||
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
|
||||||
</AssociationSet>
|
|
||||||
<AssociationSet Name="FK_RegionRoomBed_RoomUuid" Association="Model.FK_RegionRoomBed_RoomUuid">
|
<AssociationSet Name="FK_RegionRoomBed_RoomUuid" Association="Model.FK_RegionRoomBed_RoomUuid">
|
||||||
<End Role="Room" EntitySet="Room" />
|
<End Role="Room" EntitySet="Room" />
|
||||||
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
||||||
</AssociationSet>
|
</AssociationSet>
|
||||||
|
<AssociationSet Name="FK_RegionRoomBed_StatusCode" Association="Model.FK_RegionRoomBed_StatusCode">
|
||||||
|
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
||||||
|
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
||||||
|
</AssociationSet>
|
||||||
</EntityContainer>
|
</EntityContainer>
|
||||||
<ComplexType Name="sp_helpdiagramdefinition_Result">
|
<ComplexType Name="sp_helpdiagramdefinition_Result">
|
||||||
<Property Type="Int32" Name="version" Nullable="true" />
|
<Property Type="Int32" Name="version" Nullable="true" />
|
||||||
@@ -4668,8 +4637,10 @@
|
|||||||
<Property Name="BookerPhone" Type="String" MaxLength="12" FixedLength="false" Unicode="true" />
|
<Property Name="BookerPhone" Type="String" MaxLength="12" FixedLength="false" Unicode="true" />
|
||||||
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
||||||
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
||||||
|
<Property Name="ActivityNum" Type="Int32" />
|
||||||
|
<Property Name="IsCancel" Type="Boolean" Nullable="false" />
|
||||||
<NavigationProperty Name="admin" Relationship="Model.FK_GuaDanOrder_Admin_CreateUser" FromRole="GuaDanOrder" ToRole="admin" />
|
<NavigationProperty Name="admin" Relationship="Model.FK_GuaDanOrder_Admin_CreateUser" FromRole="GuaDanOrder" ToRole="admin" />
|
||||||
<NavigationProperty Name="follower" Relationship="Model.FK_GuaDanOrder_Followers" FromRole="GuaDanOrder" ToRole="follower" />
|
<NavigationProperty Name="followers" Relationship="Model.FK_GuaDanOrder_Followers" FromRole="GuaDanOrder" ToRole="follower" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="GuaDanOrderGuest">
|
<EntityType Name="GuaDanOrderGuest">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -4683,11 +4654,12 @@
|
|||||||
<Property Name="BedUuid" Type="Guid" />
|
<Property Name="BedUuid" Type="Guid" />
|
||||||
<Property Name="CheckInAt" Type="DateTime" Precision="0" />
|
<Property Name="CheckInAt" Type="DateTime" Precision="0" />
|
||||||
<Property Name="CheckOutAt" Type="DateTime" Precision="0" />
|
<Property Name="CheckOutAt" Type="DateTime" Precision="0" />
|
||||||
<Property Name="statusUuid" Type="Guid" />
|
<Property Name="StatusCode" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||||
<NavigationProperty Name="follower" Relationship="Model.FK_GuaDanOrderGuest_FOLLOWERS" FromRole="GuaDanOrderGuest" ToRole="follower" />
|
<NavigationProperty Name="followers" Relationship="Model.FK_GuaDanOrderGuest_FOLLOWERS" FromRole="GuaDanOrderGuest" ToRole="follower" />
|
||||||
<NavigationProperty Name="RegionRoomBed" Relationship="Model.FK_GuaDanOrderGuest_BedUuid" FromRole="GuaDanOrderGuest" ToRole="RegionRoomBed" />
|
<NavigationProperty Name="RegionRoomBed" Relationship="Model.FK_GuaDanOrderGuest_BedUuid" FromRole="GuaDanOrderGuest" ToRole="RegionRoomBed" />
|
||||||
<NavigationProperty Name="Room" Relationship="Model.FK_GuaDanOrderGuest_RoomUuid" FromRole="GuaDanOrderGuest" ToRole="Room" />
|
<NavigationProperty Name="Room" Relationship="Model.FK_GuaDanOrderGuest_RoomUuid" FromRole="GuaDanOrderGuest" ToRole="Room" />
|
||||||
<NavigationProperty Name="RegionRoomBedStatus" Relationship="Model.FK_GuaDanOrderGuest_Status" FromRole="GuaDanOrderGuest" ToRole="RegionRoomBedStatus" />
|
<NavigationProperty Name="RegionRoomBedStatus" Relationship="Model.FK_GuaDanOrderGuest_StatusCode" FromRole="GuaDanOrderGuest" ToRole="RegionRoomBedStatus" />
|
||||||
|
<NavigationProperty Name="RegionAndRoomAndBedSchedule" Relationship="Model.FK_Schedule_GuaDanOrderGuest" FromRole="GuaDanOrderGuest" ToRole="RegionAndRoomAndBedSchedule" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="GuadanTimeSetting">
|
<EntityType Name="GuadanTimeSetting">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -4736,7 +4708,9 @@
|
|||||||
<Property Name="TargetUuid" Type="Guid" />
|
<Property Name="TargetUuid" Type="Guid" />
|
||||||
<Property Name="GuaDanOrderNo" Type="String" MaxLength="20" FixedLength="false" Unicode="true" />
|
<Property Name="GuaDanOrderNo" Type="String" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||||
<Property Name="ScheduleDate" Type="DateTime" Precision="0" />
|
<Property Name="ScheduleDate" Type="DateTime" Precision="0" />
|
||||||
<Property Name="IsActive" Type="Boolean" Nullable="false" />
|
<Property Name="IsCancel" Type="Boolean" Nullable="false" />
|
||||||
|
<Property Name="GuaDanOrderGuestUuid" Type="Guid" />
|
||||||
|
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_Schedule_GuaDanOrderGuest" FromRole="RegionAndRoomAndBedSchedule" ToRole="GuaDanOrderGuest" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="RegionRoomBed">
|
<EntityType Name="RegionRoomBed">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -4748,23 +4722,22 @@
|
|||||||
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
||||||
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
||||||
<Property Name="RoomUuid" Type="Guid" Nullable="false" />
|
<Property Name="RoomUuid" Type="Guid" Nullable="false" />
|
||||||
<Property Name="StatusUuid" Type="Guid" />
|
<Property Name="StatusCode" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||||
<NavigationProperty Name="GuaDanOrderGuests" Relationship="Model.FK_GuaDanOrderGuest_BedUuid" FromRole="RegionRoomBed" ToRole="GuaDanOrderGuest" />
|
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_GuaDanOrderGuest_BedUuid" FromRole="RegionRoomBed" ToRole="GuaDanOrderGuest" />
|
||||||
<NavigationProperty Name="RegionRoomBedStatus" Relationship="Model.FK_RegionRoomBed_RegionRoomBedStatus" FromRole="RegionRoomBed" ToRole="RegionRoomBedStatus" />
|
|
||||||
<NavigationProperty Name="Room" Relationship="Model.FK_RegionRoomBed_RoomUuid" FromRole="RegionRoomBed" ToRole="Room" />
|
<NavigationProperty Name="Room" Relationship="Model.FK_RegionRoomBed_RoomUuid" FromRole="RegionRoomBed" ToRole="Room" />
|
||||||
|
<NavigationProperty Name="RegionRoomBedStatus" Relationship="Model.FK_RegionRoomBed_StatusCode" FromRole="RegionRoomBed" ToRole="RegionRoomBedStatus" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="RegionRoomBedStatus">
|
<EntityType Name="RegionRoomBedStatus">
|
||||||
<Key>
|
<Key>
|
||||||
<PropertyRef Name="Uuid" />
|
<PropertyRef Name="Code" />
|
||||||
</Key>
|
</Key>
|
||||||
<Property Name="Code" Type="String" MaxLength="20" FixedLength="false" Unicode="true" />
|
<Property Name="Code" 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="Name" Type="String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
|
||||||
<Property Name="Description" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
|
<Property Name="Description" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
|
||||||
<Property Name="Category" Type="Int32" />
|
<Property Name="Category" Type="Int32" />
|
||||||
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
||||||
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_GuaDanOrderGuest_StatusCode" FromRole="RegionRoomBedStatus" ToRole="GuaDanOrderGuest" />
|
||||||
<NavigationProperty Name="GuaDanOrderGuests" Relationship="Model.FK_GuaDanOrderGuest_Status" FromRole="RegionRoomBedStatus" ToRole="GuaDanOrderGuest" />
|
<NavigationProperty Name="RegionRoomBed" Relationship="Model.FK_RegionRoomBed_StatusCode" FromRole="RegionRoomBedStatus" ToRole="RegionRoomBed" />
|
||||||
<NavigationProperty Name="RegionRoomBeds" Relationship="Model.FK_RegionRoomBed_RegionRoomBedStatus" FromRole="RegionRoomBedStatus" ToRole="RegionRoomBed" />
|
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="RegionType">
|
<EntityType Name="RegionType">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -4776,7 +4749,7 @@
|
|||||||
<Property Name="CreateAt" Type="DateTime" Precision="3" />
|
<Property Name="CreateAt" Type="DateTime" Precision="3" />
|
||||||
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
||||||
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
||||||
<NavigationProperty Name="Regions" Relationship="Model.FK_Region_RegionTypeUuid" FromRole="RegionType" ToRole="Region" />
|
<NavigationProperty Name="Region" Relationship="Model.FK_Region_RegionTypeUuid" FromRole="RegionType" ToRole="Region" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="Room">
|
<EntityType Name="Room">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -4791,7 +4764,7 @@
|
|||||||
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
<Property Name="IsDeleted" Type="Boolean" Nullable="false" />
|
||||||
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
<Property Name="Uuid" Type="Guid" Nullable="false" />
|
||||||
<Property Name="RegionUuid" Type="Guid" Nullable="false" />
|
<Property Name="RegionUuid" Type="Guid" Nullable="false" />
|
||||||
<NavigationProperty Name="GuaDanOrderGuests" Relationship="Model.FK_GuaDanOrderGuest_RoomUuid" FromRole="Room" ToRole="GuaDanOrderGuest" />
|
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_GuaDanOrderGuest_RoomUuid" FromRole="Room" ToRole="GuaDanOrderGuest" />
|
||||||
<NavigationProperty Name="Region" Relationship="Model.FK_Room_Region" FromRole="Room" ToRole="Region" />
|
<NavigationProperty Name="Region" Relationship="Model.FK_Room_Region" FromRole="Room" ToRole="Region" />
|
||||||
<NavigationProperty Name="RegionRoomBed" Relationship="Model.FK_RegionRoomBed_RoomUuid" FromRole="Room" ToRole="RegionRoomBed" />
|
<NavigationProperty Name="RegionRoomBed" Relationship="Model.FK_RegionRoomBed_RoomUuid" FromRole="Room" ToRole="RegionRoomBed" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
@@ -4855,15 +4828,27 @@
|
|||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
<Association Name="FK_GuaDanOrderGuest_Status">
|
<Association Name="FK_GuaDanOrderGuest_StatusCode">
|
||||||
<End Type="Model.RegionRoomBedStatus" Role="RegionRoomBedStatus" Multiplicity="0..1" />
|
<End Type="Model.RegionRoomBedStatus" Role="RegionRoomBedStatus" Multiplicity="1" />
|
||||||
<End Type="Model.GuaDanOrderGuest" Role="GuaDanOrderGuest" Multiplicity="*" />
|
<End Type="Model.GuaDanOrderGuest" Role="GuaDanOrderGuest" Multiplicity="*" />
|
||||||
<ReferentialConstraint>
|
<ReferentialConstraint>
|
||||||
<Principal Role="RegionRoomBedStatus">
|
<Principal Role="RegionRoomBedStatus">
|
||||||
<PropertyRef Name="Uuid" />
|
<PropertyRef Name="Code" />
|
||||||
</Principal>
|
</Principal>
|
||||||
<Dependent Role="GuaDanOrderGuest">
|
<Dependent Role="GuaDanOrderGuest">
|
||||||
<PropertyRef Name="statusUuid" />
|
<PropertyRef Name="StatusCode" />
|
||||||
|
</Dependent>
|
||||||
|
</ReferentialConstraint>
|
||||||
|
</Association>
|
||||||
|
<Association Name="FK_Schedule_GuaDanOrderGuest">
|
||||||
|
<End Type="Model.GuaDanOrderGuest" Role="GuaDanOrderGuest" Multiplicity="0..1" />
|
||||||
|
<End Type="Model.RegionAndRoomAndBedSchedule" Role="RegionAndRoomAndBedSchedule" Multiplicity="*" />
|
||||||
|
<ReferentialConstraint>
|
||||||
|
<Principal Role="GuaDanOrderGuest">
|
||||||
|
<PropertyRef Name="Uuid" />
|
||||||
|
</Principal>
|
||||||
|
<Dependent Role="RegionAndRoomAndBedSchedule">
|
||||||
|
<PropertyRef Name="GuaDanOrderGuestUuid" />
|
||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
@@ -4903,18 +4888,6 @@
|
|||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
<Association Name="FK_RegionRoomBed_RegionRoomBedStatus">
|
|
||||||
<End Type="Model.RegionRoomBedStatus" Role="RegionRoomBedStatus" Multiplicity="0..1" />
|
|
||||||
<End Type="Model.RegionRoomBed" Role="RegionRoomBed" Multiplicity="*" />
|
|
||||||
<ReferentialConstraint>
|
|
||||||
<Principal Role="RegionRoomBedStatus">
|
|
||||||
<PropertyRef Name="Uuid" />
|
|
||||||
</Principal>
|
|
||||||
<Dependent Role="RegionRoomBed">
|
|
||||||
<PropertyRef Name="StatusUuid" />
|
|
||||||
</Dependent>
|
|
||||||
</ReferentialConstraint>
|
|
||||||
</Association>
|
|
||||||
<Association Name="FK_RegionRoomBed_RoomUuid">
|
<Association Name="FK_RegionRoomBed_RoomUuid">
|
||||||
<End Type="Model.Room" Role="Room" Multiplicity="1" />
|
<End Type="Model.Room" Role="Room" Multiplicity="1" />
|
||||||
<End Type="Model.RegionRoomBed" Role="RegionRoomBed" Multiplicity="*" />
|
<End Type="Model.RegionRoomBed" Role="RegionRoomBed" Multiplicity="*" />
|
||||||
@@ -4927,6 +4900,18 @@
|
|||||||
</Dependent>
|
</Dependent>
|
||||||
</ReferentialConstraint>
|
</ReferentialConstraint>
|
||||||
</Association>
|
</Association>
|
||||||
|
<Association Name="FK_RegionRoomBed_StatusCode">
|
||||||
|
<End Type="Model.RegionRoomBedStatus" Role="RegionRoomBedStatus" Multiplicity="1" />
|
||||||
|
<End Type="Model.RegionRoomBed" Role="RegionRoomBed" Multiplicity="*" />
|
||||||
|
<ReferentialConstraint>
|
||||||
|
<Principal Role="RegionRoomBedStatus">
|
||||||
|
<PropertyRef Name="Code" />
|
||||||
|
</Principal>
|
||||||
|
<Dependent Role="RegionRoomBed">
|
||||||
|
<PropertyRef Name="StatusCode" />
|
||||||
|
</Dependent>
|
||||||
|
</ReferentialConstraint>
|
||||||
|
</Association>
|
||||||
</Schema>
|
</Schema>
|
||||||
</edmx:ConceptualModels>
|
</edmx:ConceptualModels>
|
||||||
<!-- C-S mapping content -->
|
<!-- C-S mapping content -->
|
||||||
@@ -5666,42 +5651,7 @@
|
|||||||
</MappingFragment>
|
</MappingFragment>
|
||||||
</EntityTypeMapping>
|
</EntityTypeMapping>
|
||||||
</EntitySetMapping>
|
</EntitySetMapping>
|
||||||
<EntitySetMapping Name="sysdiagrams">
|
|
||||||
<EntityTypeMapping TypeName="Model.sysdiagram">
|
|
||||||
<MappingFragment StoreEntitySet="sysdiagrams">
|
|
||||||
<ScalarProperty Name="name" ColumnName="name" />
|
|
||||||
<ScalarProperty Name="principal_id" ColumnName="principal_id" />
|
|
||||||
<ScalarProperty Name="diagram_id" ColumnName="diagram_id" />
|
|
||||||
<ScalarProperty Name="version" ColumnName="version" />
|
|
||||||
<ScalarProperty Name="definition" ColumnName="definition" />
|
|
||||||
</MappingFragment>
|
|
||||||
</EntityTypeMapping>
|
|
||||||
</EntitySetMapping>
|
|
||||||
<FunctionImportMapping FunctionImportName="pager_eztrust" FunctionName="Model.Store.pager_eztrust" />
|
<FunctionImportMapping FunctionImportName="pager_eztrust" FunctionName="Model.Store.pager_eztrust" />
|
||||||
<FunctionImportMapping FunctionImportName="sp_alterdiagram" FunctionName="Model.Store.sp_alterdiagram" />
|
|
||||||
<FunctionImportMapping FunctionImportName="sp_creatediagram" FunctionName="Model.Store.sp_creatediagram" />
|
|
||||||
<FunctionImportMapping FunctionImportName="sp_dropdiagram" FunctionName="Model.Store.sp_dropdiagram" />
|
|
||||||
<FunctionImportMapping FunctionImportName="sp_helpdiagramdefinition" FunctionName="Model.Store.sp_helpdiagramdefinition">
|
|
||||||
<ResultMapping>
|
|
||||||
<ComplexTypeMapping TypeName="Model.sp_helpdiagramdefinition_Result">
|
|
||||||
<ScalarProperty Name="version" ColumnName="version" />
|
|
||||||
<ScalarProperty Name="definition" ColumnName="definition" />
|
|
||||||
</ComplexTypeMapping>
|
|
||||||
</ResultMapping>
|
|
||||||
</FunctionImportMapping>
|
|
||||||
<FunctionImportMapping FunctionImportName="sp_helpdiagrams" FunctionName="Model.Store.sp_helpdiagrams">
|
|
||||||
<ResultMapping>
|
|
||||||
<ComplexTypeMapping TypeName="Model.sp_helpdiagrams_Result">
|
|
||||||
<ScalarProperty Name="Database" ColumnName="Database" />
|
|
||||||
<ScalarProperty Name="Name" ColumnName="Name" />
|
|
||||||
<ScalarProperty Name="ID" ColumnName="ID" />
|
|
||||||
<ScalarProperty Name="Owner" ColumnName="Owner" />
|
|
||||||
<ScalarProperty Name="OwnerID" ColumnName="OwnerID" />
|
|
||||||
</ComplexTypeMapping>
|
|
||||||
</ResultMapping>
|
|
||||||
</FunctionImportMapping>
|
|
||||||
<FunctionImportMapping FunctionImportName="sp_renamediagram" FunctionName="Model.Store.sp_renamediagram" />
|
|
||||||
<FunctionImportMapping FunctionImportName="sp_upgraddiagrams" FunctionName="Model.Store.sp_upgraddiagrams" />
|
|
||||||
<EntitySetMapping Name="act_bom">
|
<EntitySetMapping Name="act_bom">
|
||||||
<EntityTypeMapping TypeName="Model.act_bom">
|
<EntityTypeMapping TypeName="Model.act_bom">
|
||||||
<MappingFragment StoreEntitySet="act_bom">
|
<MappingFragment StoreEntitySet="act_bom">
|
||||||
@@ -5803,6 +5753,8 @@
|
|||||||
<EntitySetMapping Name="GuaDanOrder">
|
<EntitySetMapping Name="GuaDanOrder">
|
||||||
<EntityTypeMapping TypeName="Model.GuaDanOrder">
|
<EntityTypeMapping TypeName="Model.GuaDanOrder">
|
||||||
<MappingFragment StoreEntitySet="GuaDanOrder">
|
<MappingFragment StoreEntitySet="GuaDanOrder">
|
||||||
|
<ScalarProperty Name="IsCancel" ColumnName="IsCancel" />
|
||||||
|
<ScalarProperty Name="ActivityNum" ColumnName="ActivityNum" />
|
||||||
<ScalarProperty Name="Uuid" ColumnName="Uuid" />
|
<ScalarProperty Name="Uuid" ColumnName="Uuid" />
|
||||||
<ScalarProperty Name="IsDeleted" ColumnName="IsDeleted" />
|
<ScalarProperty Name="IsDeleted" ColumnName="IsDeleted" />
|
||||||
<ScalarProperty Name="BookerPhone" ColumnName="BookerPhone" />
|
<ScalarProperty Name="BookerPhone" ColumnName="BookerPhone" />
|
||||||
@@ -5821,7 +5773,7 @@
|
|||||||
<EntitySetMapping Name="GuaDanOrderGuest">
|
<EntitySetMapping Name="GuaDanOrderGuest">
|
||||||
<EntityTypeMapping TypeName="Model.GuaDanOrderGuest">
|
<EntityTypeMapping TypeName="Model.GuaDanOrderGuest">
|
||||||
<MappingFragment StoreEntitySet="GuaDanOrderGuest">
|
<MappingFragment StoreEntitySet="GuaDanOrderGuest">
|
||||||
<ScalarProperty Name="statusUuid" ColumnName="statusUuid" />
|
<ScalarProperty Name="StatusCode" ColumnName="StatusCode" />
|
||||||
<ScalarProperty Name="CheckOutAt" ColumnName="CheckOutAt" />
|
<ScalarProperty Name="CheckOutAt" ColumnName="CheckOutAt" />
|
||||||
<ScalarProperty Name="CheckInAt" ColumnName="CheckInAt" />
|
<ScalarProperty Name="CheckInAt" ColumnName="CheckInAt" />
|
||||||
<ScalarProperty Name="BedUuid" ColumnName="BedUuid" />
|
<ScalarProperty Name="BedUuid" ColumnName="BedUuid" />
|
||||||
@@ -5867,7 +5819,8 @@
|
|||||||
<EntitySetMapping Name="RegionAndRoomAndBedSchedule">
|
<EntitySetMapping Name="RegionAndRoomAndBedSchedule">
|
||||||
<EntityTypeMapping TypeName="Model.RegionAndRoomAndBedSchedule">
|
<EntityTypeMapping TypeName="Model.RegionAndRoomAndBedSchedule">
|
||||||
<MappingFragment StoreEntitySet="RegionAndRoomAndBedSchedule">
|
<MappingFragment StoreEntitySet="RegionAndRoomAndBedSchedule">
|
||||||
<ScalarProperty Name="IsActive" ColumnName="IsActive" />
|
<ScalarProperty Name="GuaDanOrderGuestUuid" ColumnName="GuaDanOrderGuestUuid" />
|
||||||
|
<ScalarProperty Name="IsCancel" ColumnName="IsCancel" />
|
||||||
<ScalarProperty Name="ScheduleDate" ColumnName="ScheduleDate" />
|
<ScalarProperty Name="ScheduleDate" ColumnName="ScheduleDate" />
|
||||||
<ScalarProperty Name="GuaDanOrderNo" ColumnName="GuaDanOrderNo" />
|
<ScalarProperty Name="GuaDanOrderNo" ColumnName="GuaDanOrderNo" />
|
||||||
<ScalarProperty Name="TargetUuid" ColumnName="TargetUuid" />
|
<ScalarProperty Name="TargetUuid" ColumnName="TargetUuid" />
|
||||||
@@ -5884,7 +5837,7 @@
|
|||||||
<EntitySetMapping Name="RegionRoomBed">
|
<EntitySetMapping Name="RegionRoomBed">
|
||||||
<EntityTypeMapping TypeName="Model.RegionRoomBed">
|
<EntityTypeMapping TypeName="Model.RegionRoomBed">
|
||||||
<MappingFragment StoreEntitySet="RegionRoomBed">
|
<MappingFragment StoreEntitySet="RegionRoomBed">
|
||||||
<ScalarProperty Name="StatusUuid" ColumnName="StatusUuid" />
|
<ScalarProperty Name="StatusCode" ColumnName="StatusCode" />
|
||||||
<ScalarProperty Name="RoomUuid" ColumnName="RoomUuid" />
|
<ScalarProperty Name="RoomUuid" ColumnName="RoomUuid" />
|
||||||
<ScalarProperty Name="Uuid" ColumnName="Uuid" />
|
<ScalarProperty Name="Uuid" ColumnName="Uuid" />
|
||||||
<ScalarProperty Name="IsDeleted" ColumnName="IsDeleted" />
|
<ScalarProperty Name="IsDeleted" ColumnName="IsDeleted" />
|
||||||
@@ -5897,7 +5850,6 @@
|
|||||||
<EntitySetMapping Name="RegionRoomBedStatus">
|
<EntitySetMapping Name="RegionRoomBedStatus">
|
||||||
<EntityTypeMapping TypeName="Model.RegionRoomBedStatus">
|
<EntityTypeMapping TypeName="Model.RegionRoomBedStatus">
|
||||||
<MappingFragment StoreEntitySet="RegionRoomBedStatus">
|
<MappingFragment StoreEntitySet="RegionRoomBedStatus">
|
||||||
<ScalarProperty Name="Uuid" ColumnName="Uuid" />
|
|
||||||
<ScalarProperty Name="IsDeleted" ColumnName="IsDeleted" />
|
<ScalarProperty Name="IsDeleted" ColumnName="IsDeleted" />
|
||||||
<ScalarProperty Name="Category" ColumnName="Category" />
|
<ScalarProperty Name="Category" ColumnName="Category" />
|
||||||
<ScalarProperty Name="Description" ColumnName="Description" />
|
<ScalarProperty Name="Description" ColumnName="Description" />
|
||||||
@@ -5947,7 +5899,7 @@
|
|||||||
<Options>
|
<Options>
|
||||||
<DesignerInfoPropertySet>
|
<DesignerInfoPropertySet>
|
||||||
<DesignerProperty Name="ValidateOnBuild" Value="true" />
|
<DesignerProperty Name="ValidateOnBuild" Value="true" />
|
||||||
<DesignerProperty Name="EnablePluralization" Value="true" />
|
<DesignerProperty Name="EnablePluralization" Value="False" />
|
||||||
<DesignerProperty Name="IncludeForeignKeysInModel" Value="true" />
|
<DesignerProperty Name="IncludeForeignKeysInModel" Value="true" />
|
||||||
<DesignerProperty Name="UseLegacyProvider" Value="false" />
|
<DesignerProperty Name="UseLegacyProvider" Value="false" />
|
||||||
<DesignerProperty Name="CodeGenerationStrategy" Value="無" />
|
<DesignerProperty Name="CodeGenerationStrategy" Value="無" />
|
||||||
|
|||||||
@@ -52,7 +52,6 @@
|
|||||||
<EntityTypeShape EntityType="Model.stock_reason" Width="1.5" PointX="14.25" PointY="33.625" IsExpanded="true" />
|
<EntityTypeShape EntityType="Model.stock_reason" Width="1.5" PointX="14.25" PointY="33.625" IsExpanded="true" />
|
||||||
<EntityTypeShape EntityType="Model.supplier" Width="1.5" PointX="14.25" PointY="36.5" IsExpanded="true" />
|
<EntityTypeShape EntityType="Model.supplier" Width="1.5" PointX="14.25" PointY="36.5" IsExpanded="true" />
|
||||||
<EntityTypeShape EntityType="Model.supplier_kind" Width="1.5" PointX="12" PointY="37.5" IsExpanded="true" />
|
<EntityTypeShape EntityType="Model.supplier_kind" Width="1.5" PointX="12" PointY="37.5" IsExpanded="true" />
|
||||||
<EntityTypeShape EntityType="Model.sysdiagram" Width="1.5" PointX="0.75" PointY="6" IsExpanded="true" />
|
|
||||||
<AssociationConnector Association="Model.FK_accounting_accounting_kind" ManuallyRouted="false" />
|
<AssociationConnector Association="Model.FK_accounting_accounting_kind" ManuallyRouted="false" />
|
||||||
<AssociationConnector Association="Model.FK_accounting_accounting_kind2" ManuallyRouted="false" />
|
<AssociationConnector Association="Model.FK_accounting_accounting_kind2" ManuallyRouted="false" />
|
||||||
<AssociationConnector Association="Model.FK_accounting_activity" ManuallyRouted="false" />
|
<AssociationConnector Association="Model.FK_accounting_activity" ManuallyRouted="false" />
|
||||||
@@ -131,26 +130,27 @@
|
|||||||
<AssociationConnector Association="Model.FK_transfer_register_actItem" />
|
<AssociationConnector Association="Model.FK_transfer_register_actItem" />
|
||||||
<AssociationConnector Association="Model.FK_transfer_register_pro_order_detail" />
|
<AssociationConnector Association="Model.FK_transfer_register_pro_order_detail" />
|
||||||
<AssociationConnector Association="Model.FK_pro_order_record_transfer_register" />
|
<AssociationConnector Association="Model.FK_pro_order_record_transfer_register" />
|
||||||
<EntityTypeShape EntityType="Model.GuaDanOrder" Width="1.5" PointX="13.375" PointY="21.25" />
|
<EntityTypeShape EntityType="Model.GuaDanOrder" Width="1.5" PointX="13.25" PointY="20.25" />
|
||||||
<EntityTypeShape EntityType="Model.GuaDanOrderGuest" Width="2.125" PointX="30.375" PointY="13.75" />
|
<EntityTypeShape EntityType="Model.GuaDanOrderGuest" Width="1.5" PointX="25.875" PointY="12.5" />
|
||||||
<EntityTypeShape EntityType="Model.GuadanTimeSetting" Width="1.5" PointX="21.375" PointY="9.125" />
|
<EntityTypeShape EntityType="Model.GuadanTimeSetting" Width="1.5" PointX="21.375" PointY="7.75" />
|
||||||
<EntityTypeShape EntityType="Model.Region" Width="1.5" PointX="23.625" PointY="3.875" />
|
<EntityTypeShape EntityType="Model.Region" Width="1.5" PointX="19.125" PointY="30.75" />
|
||||||
<EntityTypeShape EntityType="Model.RegionAndRoomAndBedSchedule" Width="1.5" PointX="23.375" PointY="9.125" />
|
<EntityTypeShape EntityType="Model.RegionAndRoomAndBedSchedule" Width="1.5" PointX="28.125" PointY="12.625" />
|
||||||
<EntityTypeShape EntityType="Model.RegionRoomBed" Width="2.125" PointX="28.125" PointY="4.625" />
|
<EntityTypeShape EntityType="Model.RegionRoomBed" Width="1.5" PointX="23.625" PointY="3.375" />
|
||||||
<EntityTypeShape EntityType="Model.RegionRoomBedStatus" Width="1.5" PointX="25.875" PointY="0.75" />
|
<EntityTypeShape EntityType="Model.RegionRoomBedStatus" Width="1.5" PointX="21.375" PointY="3.625" />
|
||||||
<EntityTypeShape EntityType="Model.RegionType" Width="1.5" PointX="21.375" PointY="4.875" />
|
<EntityTypeShape EntityType="Model.RegionType" Width="1.5" PointX="16.875" PointY="31.625" />
|
||||||
<EntityTypeShape EntityType="Model.Room" Width="1.5" PointX="25.875" PointY="4.375" />
|
<EntityTypeShape EntityType="Model.Room" Width="1.5" PointX="21.375" PointY="31.125" />
|
||||||
<AssociationConnector Association="Model.FK_GuaDanOrder_Admin_CreateUser" />
|
<AssociationConnector Association="Model.FK_GuaDanOrder_Admin_CreateUser" />
|
||||||
<AssociationConnector Association="Model.FK_GuaDanOrder_Followers" />
|
<AssociationConnector Association="Model.FK_GuaDanOrder_Followers" />
|
||||||
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_FOLLOWERS" />
|
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_FOLLOWERS" />
|
||||||
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_BedUuid" />
|
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_BedUuid" />
|
||||||
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_RoomUuid" />
|
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_RoomUuid" />
|
||||||
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_Status" />
|
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_StatusCode" />
|
||||||
|
<AssociationConnector Association="Model.FK_Schedule_GuaDanOrderGuest" />
|
||||||
<AssociationConnector Association="Model.FK_Region_ParentUuid" />
|
<AssociationConnector Association="Model.FK_Region_ParentUuid" />
|
||||||
<AssociationConnector Association="Model.FK_Region_RegionTypeUuid" />
|
<AssociationConnector Association="Model.FK_Region_RegionTypeUuid" />
|
||||||
<AssociationConnector Association="Model.FK_Room_Region" />
|
<AssociationConnector Association="Model.FK_Room_Region" />
|
||||||
<AssociationConnector Association="Model.FK_RegionRoomBed_RegionRoomBedStatus" />
|
|
||||||
<AssociationConnector Association="Model.FK_RegionRoomBed_RoomUuid" />
|
<AssociationConnector Association="Model.FK_RegionRoomBed_RoomUuid" />
|
||||||
|
<AssociationConnector Association="Model.FK_RegionRoomBed_StatusCode" />
|
||||||
</Diagram>
|
</Diagram>
|
||||||
</edmx:Diagrams>
|
</edmx:Diagrams>
|
||||||
</edmx:Designer>
|
</edmx:Designer>
|
||||||
|
|||||||
57
web/App_Code/Model/Partial/GuaDanOrderGuest.cs
Normal file
57
web/App_Code/Model/Partial/GuaDanOrderGuest.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Entity;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GuaDanOrderGuest 的摘要描述
|
||||||
|
/// </summary>
|
||||||
|
namespace Model
|
||||||
|
{
|
||||||
|
public partial class GuaDanOrderGuest
|
||||||
|
{
|
||||||
|
// 状态常量定义
|
||||||
|
public const string STATUS_BOOKED = "401"; // 预订成功
|
||||||
|
public const string STATUS_CHECKED_IN = "402"; // 已入住
|
||||||
|
public const string STATUS_CHECKED_OUT = "403"; // 已退房
|
||||||
|
public const string STATUS_CANCELLED = "404"; // 已取消
|
||||||
|
|
||||||
|
public static bool IsStatusTransitionValid(ezEntities db, string targetStatus, Guid guestId)
|
||||||
|
{
|
||||||
|
// 获取当前客人对象
|
||||||
|
GuaDanOrderGuest currentGuest = db.GuaDanOrderGuest.Find(guestId);
|
||||||
|
if (currentGuest == null)
|
||||||
|
{
|
||||||
|
// 如果没有客人对象,只能创建新的预订
|
||||||
|
return targetStatus == STATUS_BOOKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安全获取当前状态(处理null情况)
|
||||||
|
string currentStatus = currentGuest.RegionRoomBedStatus?.Code;
|
||||||
|
|
||||||
|
// 如果当前状态为空,只能进入预订成功状态
|
||||||
|
if (string.IsNullOrEmpty(currentStatus))
|
||||||
|
{
|
||||||
|
return targetStatus == STATUS_BOOKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义有效的状态转换规则
|
||||||
|
var validTransitions = new Dictionary<string, List<string>>
|
||||||
|
{
|
||||||
|
{ STATUS_BOOKED, new List<string> { STATUS_CHECKED_IN, STATUS_CANCELLED } },
|
||||||
|
{ STATUS_CHECKED_IN, new List<string> { STATUS_CHECKED_OUT } },
|
||||||
|
{ STATUS_CHECKED_OUT, new List<string> { } }, // 终态,不能再转换
|
||||||
|
{ STATUS_CANCELLED, new List<string> { } } // 终态,不能再转换
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查转换是否有效
|
||||||
|
if (validTransitions.ContainsKey(currentStatus))
|
||||||
|
{
|
||||||
|
return validTransitions[currentStatus].Contains(targetStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // 未知的当前状态
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,7 +58,7 @@ namespace Model
|
|||||||
|
|
||||||
// 找出在日期範圍內被占用的床位 Uuid(包括長期占用 ScheduleDate = null)
|
// 找出在日期範圍內被占用的床位 Uuid(包括長期占用 ScheduleDate = null)
|
||||||
var busyBedUuidsQuery = db.RegionAndRoomAndBedSchedule
|
var busyBedUuidsQuery = db.RegionAndRoomAndBedSchedule
|
||||||
.Where(s => s.IsDeleted == false && s.IsActive
|
.Where(s => s.IsDeleted == false && !s.IsCancel
|
||||||
&& (s.ScheduleDate == null
|
&& (s.ScheduleDate == null
|
||||||
|| (end.HasValue
|
|| (end.HasValue
|
||||||
&& s.ScheduleDate >= start
|
&& s.ScheduleDate >= start
|
||||||
@@ -79,25 +79,28 @@ namespace Model
|
|||||||
public static async Task<bool> IsBedAvailableAsync(ezEntities db, Guid targetUuid, DateTime start, DateTime? end)
|
public static async Task<bool> IsBedAvailableAsync(ezEntities db, Guid targetUuid, DateTime start, DateTime? end)
|
||||||
{
|
{
|
||||||
// 如果 end 為 null,表示長期占用,直接判斷是否已有長期占用
|
// 如果 end 為 null,表示長期占用,直接判斷是否已有長期占用
|
||||||
|
//不包含结束时间那一天
|
||||||
if (end == null)
|
if (end == null)
|
||||||
{
|
{
|
||||||
var hasLongTerm = await db.RegionAndRoomAndBedSchedule
|
var hasLongTerm = await db.RegionAndRoomAndBedSchedule
|
||||||
.AnyAsync(s => s.IsDeleted == false
|
.AnyAsync(s => s.IsDeleted == false
|
||||||
&& s.IsActive
|
&& !s.IsCancel
|
||||||
&& s.TargetUuid == targetUuid
|
&& s.TargetUuid == targetUuid
|
||||||
&& s.ScheduleDate == null);
|
&& s.ScheduleDate == null);
|
||||||
return !hasLongTerm;
|
return !hasLongTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 短期占用,查詢每日排程中有無衝突
|
// 短期占用,查詢每日排程中有無衝突
|
||||||
var totalDays = (end.Value.Date - start.Date).Days + 1;
|
var totalDays = (end.Value.Date - start.Date).Days;
|
||||||
for (int i = 0; i < totalDays; i++)
|
for (int i = 0; i < totalDays; i++)
|
||||||
{
|
{
|
||||||
var date = start.Date.AddDays(i);
|
var date = start.Date.AddDays(i);
|
||||||
|
|
||||||
var conflict = await db.RegionAndRoomAndBedSchedule
|
var conflict = await db.RegionAndRoomAndBedSchedule
|
||||||
|
.Where(s => s.GuaDanOrderGuest.StatusCode != GuaDanOrderGuest.STATUS_CANCELLED)
|
||||||
|
.Where(s => s.GuaDanOrderGuest.StatusCode != GuaDanOrderGuest.STATUS_CHECKED_OUT)
|
||||||
.AnyAsync(s => s.IsDeleted == false
|
.AnyAsync(s => s.IsDeleted == false
|
||||||
&& s.IsActive
|
&& !s.IsCancel
|
||||||
&& s.TargetUuid == targetUuid
|
&& s.TargetUuid == targetUuid
|
||||||
&& s.ScheduleDate == date);
|
&& s.ScheduleDate == date);
|
||||||
|
|
||||||
@@ -114,7 +117,10 @@ namespace Model
|
|||||||
|
|
||||||
// 找出所有在日期範圍內被占用的床位
|
// 找出所有在日期範圍內被占用的床位
|
||||||
var busyBedUuids = await db.RegionAndRoomAndBedSchedule
|
var busyBedUuids = await db.RegionAndRoomAndBedSchedule
|
||||||
.Where(s => s.IsDeleted == false && s.IsActive
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "403")
|
||||||
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "404")
|
||||||
|
.Where(a => a.IsCancel == false)
|
||||||
|
.Where(s => s.IsDeleted == false
|
||||||
&& (s.ScheduleDate == null // 長期占用
|
&& (s.ScheduleDate == null // 長期占用
|
||||||
|| (s.ScheduleDate >= start && s.ScheduleDate <= end)))
|
|| (s.ScheduleDate >= start && s.ScheduleDate <= end)))
|
||||||
.Select(s => s.TargetUuid)
|
.Select(s => s.TargetUuid)
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ namespace Model
|
|||||||
{
|
{
|
||||||
public partial class RegionRoomBed
|
public partial class RegionRoomBed
|
||||||
{
|
{
|
||||||
|
public const string STATUS_BED_FREE = "101"; // 空閒,可使用
|
||||||
|
public const string STATUS_BED_OCCUPIED = "102"; // 已佔用
|
||||||
|
public const string STATUS_BED_MAINTENANCE = "103"; // 維護中,不可使用
|
||||||
public bool IsAvailable()
|
public bool IsAvailable()
|
||||||
{
|
{
|
||||||
//判断床位是否可用:自身是否启用
|
//判断床位是否可用:自身是否启用
|
||||||
@@ -34,7 +37,9 @@ namespace Model
|
|||||||
// 如果資料庫 ScheduleDate 是 date 型別,本身沒有時間部分,可以直接比較
|
// 如果資料庫 ScheduleDate 是 date 型別,本身沒有時間部分,可以直接比較
|
||||||
var conflict = _db.RegionAndRoomAndBedSchedule.Any(s =>
|
var conflict = _db.RegionAndRoomAndBedSchedule.Any(s =>
|
||||||
s.TargetUuid == this.Uuid &&
|
s.TargetUuid == this.Uuid &&
|
||||||
s.IsActive &&
|
s.GuaDanOrderGuest.StatusCode != "403" &&
|
||||||
|
s.GuaDanOrderGuest.StatusCode != "404" &&
|
||||||
|
!s.IsCancel &&
|
||||||
!s.IsDeleted &&
|
!s.IsDeleted &&
|
||||||
(
|
(
|
||||||
s.ScheduleDate == null || // 長期占用
|
s.ScheduleDate == null || // 長期占用
|
||||||
@@ -46,5 +51,6 @@ namespace Model
|
|||||||
|
|
||||||
return !conflict;
|
return !conflict;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,5 +19,6 @@ public class GuaDanOrderView
|
|||||||
public string bookerName { get; set; }
|
public string bookerName { get; set; }
|
||||||
public string bookerPhone { get; set; }
|
public string bookerPhone { get; set; }
|
||||||
public int? bookerFollowerNum { get; set; }
|
public int? bookerFollowerNum { get; set; }
|
||||||
|
public int? activityNum { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,73 +1,38 @@
|
|||||||
using System;
|
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;
|
||||||
using System.Collections.Generic;
|
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.Collections.Specialized;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.Design;
|
using System.ComponentModel.Design;
|
||||||
using System.ComponentModel.Design.Serialization;
|
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;
|
||||||
|
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.Security.Principal;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Web;
|
||||||
using System.Web.Caching;
|
using System.Web.Caching;
|
||||||
using System.Web.ModelBinding;
|
using System.Web.ModelBinding;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
|
using System.Web.Security;
|
||||||
using System.Web.SessionState;
|
using System.Web.SessionState;
|
||||||
|
using System.Web.UI;
|
||||||
using System.Web.UI.Adapters;
|
using System.Web.UI.Adapters;
|
||||||
using System.Web.UI.HtmlControls;
|
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 System.Web.UI.WebControls;
|
||||||
using Newtonsoft.Json;
|
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
|
namespace Model.ViewModel
|
||||||
|
|||||||
34
web/App_Code/StatusTransitionManager.cs
Normal file
34
web/App_Code/StatusTransitionManager.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Model
|
||||||
|
{
|
||||||
|
public static class StatusTransitionManager
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<string, List<string>> transitions =
|
||||||
|
new Dictionary<string, List<string>>
|
||||||
|
{
|
||||||
|
// 掛單狀態
|
||||||
|
{ "401", new List<string> { "402", "404" } },
|
||||||
|
{ "402", new List<string> { "403" } },
|
||||||
|
{ "403", new List<string>() },
|
||||||
|
{ "404", new List<string>() },
|
||||||
|
|
||||||
|
// 床位狀態
|
||||||
|
{ "101", new List<string> {"101", "102","103"} },
|
||||||
|
{ "102", new List<string> { "101" } },
|
||||||
|
{ "103", new List<string> { "101" } },
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool CanTransition(string currentCode, string targetCode)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(currentCode))
|
||||||
|
{
|
||||||
|
return targetCode == "401" || targetCode == "402" || targetCode == "101";
|
||||||
|
}
|
||||||
|
if(string.IsNullOrEmpty(targetCode))
|
||||||
|
{ return false; }
|
||||||
|
return transitions.ContainsKey(currentCode) &&
|
||||||
|
transitions[currentCode].Contains(targetCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
web/App_Code/api/ActivityStatisticsController.cs
Normal file
73
web/App_Code/api/ActivityStatisticsController.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Http;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ActivityStatisticsController 的摘要描述
|
||||||
|
/// </summary>
|
||||||
|
public class ActivityStatisticsController: ApiController
|
||||||
|
{
|
||||||
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/activity/statistics/summary")]
|
||||||
|
public IHttpActionResult GetStatisticsSummary([FromUri] int? activity_num =null)
|
||||||
|
{
|
||||||
|
if (activity_num == null)
|
||||||
|
{
|
||||||
|
return BadRequest("活动Id不能为空");
|
||||||
|
}
|
||||||
|
var now = DateTime.Now;
|
||||||
|
var pre_order_query = _db.pro_order.Where(a => a.activity_num == activity_num);
|
||||||
|
var totalApplicants = pre_order_query.Count();
|
||||||
|
var maleApplicants = pre_order_query.Where(a => a.follower.sex == "男眾").Count();
|
||||||
|
|
||||||
|
var pro_order_detail_query = _db.pro_order_detail
|
||||||
|
.Where(d => d.pro_order.activity_num == activity_num);
|
||||||
|
var result = new
|
||||||
|
{
|
||||||
|
reportDate = now.ToString("yyyy/MM/dd HH:mm:ss"),
|
||||||
|
totalApplicants = totalApplicants, //报名总人数
|
||||||
|
maleApplicants = maleApplicants, //男
|
||||||
|
femaleApplicants = totalApplicants - maleApplicants,//女
|
||||||
|
donation = new
|
||||||
|
{
|
||||||
|
total = 158000,//总功德金
|
||||||
|
received = 150000,//已收功德金
|
||||||
|
unreceived = 8000//未收功德金
|
||||||
|
},
|
||||||
|
items = new[]//功德项目,这个的功德项目要根据活动预设的功德项目来做统计,就是这个活动有那些可报名的功德项目
|
||||||
|
{
|
||||||
|
new { name = "總功德主", count = "10人" },
|
||||||
|
new { name = "利益主", count = "15人" },
|
||||||
|
new { name = "個人大牌", count = "50人" },
|
||||||
|
new { name = "供僧", count = "45人" }
|
||||||
|
},
|
||||||
|
plaques = new[]//牌位
|
||||||
|
{
|
||||||
|
new { name = "總牌位數", count = pro_order_detail_query.Count() },
|
||||||
|
new { name = "消災-大牌位", count = 101 },
|
||||||
|
new { name = "超冤-大牌位", count =10 },
|
||||||
|
new { name = "消災-個人大牌", count =10 },
|
||||||
|
new { name = "超冤-個人大牌", count = 10 },
|
||||||
|
new { name = "超薦-個人大牌", count = 10 },
|
||||||
|
new { name = "消災-個人中牌", count = 10 },
|
||||||
|
new { name = "超冤-個人中牌", count = 10 },
|
||||||
|
new { name = "超薦-個人中牌", count = 10 },
|
||||||
|
new { name = "消災-隨喜牌位", count = 10 },
|
||||||
|
new { name = "超冤-隨喜牌位", count = 10 },
|
||||||
|
new { name = "超薦-隨喜牌位", count = 10 },
|
||||||
|
new { name = "消災-常年牌位", count = 10 },
|
||||||
|
new { name = "超冤-常年牌位", count = 10 },
|
||||||
|
new { name = "超薦-常年牌位", count = 10 },
|
||||||
|
new { name = "消災-急立牌位", count = 10 },
|
||||||
|
new { name = "超薦-急立牌位", count = 10 },
|
||||||
|
new { name = "超冤-急立牌位", count = 101 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
184
web/App_Code/api/HandleBedInUsedController.cs
Normal file
184
web/App_Code/api/HandleBedInUsedController.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Http;
|
||||||
|
using System.Web.Http.Results;
|
||||||
|
using static GuaDanStatusCode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HandleBedInUsedController 的摘要描述
|
||||||
|
/// </summary>
|
||||||
|
public class HandleBedInUsedController : ApiController
|
||||||
|
{
|
||||||
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
|
public HandleBedInUsedController()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// TODO: 在這裡新增建構函式邏輯
|
||||||
|
//
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/bed/inuse/list")]
|
||||||
|
public IHttpActionResult Get([FromBody] UuidModel uuidModel)
|
||||||
|
{
|
||||||
|
//獲取已被預約或者正在入住的床位,如果有指定就會查詢指定條件,如果沒有指定就會返回所有
|
||||||
|
var query = _db.GuaDanOrderGuest
|
||||||
|
.Where(gd => gd.StatusCode == GuaDanStatusCode.Guadan.CheckedIn
|
||||||
|
|| gd.StatusCode == GuaDanStatusCode.Guadan.Booked).ToList();
|
||||||
|
if (uuidModel.bedUuid.HasValue)
|
||||||
|
{
|
||||||
|
// 優先按床位查詢
|
||||||
|
query = query.Where(g => g.BedUuid == uuidModel.bedUuid.Value).ToList();
|
||||||
|
}
|
||||||
|
else if (uuidModel.roomUuid.HasValue)
|
||||||
|
{
|
||||||
|
// 如果沒有 bed,但有 room
|
||||||
|
query = query.Where(g => g.RoomUuid == uuidModel.roomUuid.Value).ToList();
|
||||||
|
}
|
||||||
|
else if (uuidModel.regionUuid.HasValue)
|
||||||
|
{
|
||||||
|
// 如果只有 region
|
||||||
|
//query = query.Where(g => g.Room.RegionUuid == uuidModel.regionUuid.Value);
|
||||||
|
query = query.Where(g => IsRegionOrAncestor(g.Room, uuidModel.regionUuid.Value)).ToList();
|
||||||
|
|
||||||
|
}
|
||||||
|
var data = query.Select(g => new
|
||||||
|
{
|
||||||
|
g.BedUuid,
|
||||||
|
g.RoomUuid,
|
||||||
|
g.Room.RegionUuid,
|
||||||
|
g.GuaDanOrderNo,
|
||||||
|
g.RegionRoomBed.Name,
|
||||||
|
fullName = GetFullBedName(g.BedUuid.Value),
|
||||||
|
g.followers.u_name,
|
||||||
|
guadan_during = new { g.CheckInAt, g.CheckOutAt },
|
||||||
|
status = new { g.StatusCode, g.RegionRoomBedStatus.Name }
|
||||||
|
});
|
||||||
|
return Ok(data.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/bed/inuse/cancel/singlebed/booking")]
|
||||||
|
public IHttpActionResult CancelSingleBedBooking([FromBody] UuidModel uuidModel)
|
||||||
|
{
|
||||||
|
if (uuidModel?.bedUuid == null)
|
||||||
|
return BadRequest("床位ID不能為空");
|
||||||
|
|
||||||
|
using (var transaction = _db.Database.BeginTransaction())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 查詢符合條件的訂單
|
||||||
|
var orders = _db.GuaDanOrderGuest
|
||||||
|
.Where(g => g.BedUuid == uuidModel.bedUuid)
|
||||||
|
.Where(g => g.StatusCode == GuaDanStatusCode.Guadan.Booked || g.StatusCode == GuaDanStatusCode.Guadan.CheckedIn)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (!orders.Any())
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
// 更新狀態
|
||||||
|
foreach (var order in orders)
|
||||||
|
{
|
||||||
|
if (!StatusTransitionManager.CanTransition(order.StatusCode, GuaDanStatusCode.Guadan.Cancelled))
|
||||||
|
{
|
||||||
|
return BadRequest("當前狀態不能被取消");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
order.StatusCode = GuaDanStatusCode.Guadan.Cancelled; // 假設Cancelled是取消狀態
|
||||||
|
}
|
||||||
|
var schedules = _db.RegionAndRoomAndBedSchedule
|
||||||
|
.Where(s => s.TargetUuid == uuidModel.bedUuid)
|
||||||
|
.Where(s => s.GuaDanOrderGuest.StatusCode == GuaDanStatusCode.Guadan.Booked
|
||||||
|
|| s.GuaDanOrderGuest.StatusCode == GuaDanStatusCode.Guadan.CheckedIn)
|
||||||
|
.ToList();
|
||||||
|
foreach (var schedule in schedules)
|
||||||
|
{
|
||||||
|
schedule.IsCancel = true;
|
||||||
|
}
|
||||||
|
_db.SaveChanges();
|
||||||
|
transaction.Commit();
|
||||||
|
|
||||||
|
return Ok(new { message = "取消成功", cancelledCount = orders.Count });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
transaction.Rollback();
|
||||||
|
return InternalServerError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/bed/inuse/region/list")]
|
||||||
|
public IHttpActionResult GetRegionList()
|
||||||
|
{
|
||||||
|
var regions = _db.Region
|
||||||
|
.Select(r => new
|
||||||
|
{
|
||||||
|
r.Uuid,
|
||||||
|
r.Name,
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
return Ok(regions);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/bed/inuse/room/list")]
|
||||||
|
public IHttpActionResult GetRoomList([FromUri] Guid? regionUuid = null)
|
||||||
|
{
|
||||||
|
var room = _db.Room.Where(r => !r.IsDeleted && r.IsActive.Value).ToList();
|
||||||
|
if (regionUuid != null)
|
||||||
|
{
|
||||||
|
room = room.Where(r => IsRegionOrAncestor(r, regionUuid.Value)).ToList();
|
||||||
|
}
|
||||||
|
var data = room.Select(r => new
|
||||||
|
{
|
||||||
|
r.Uuid,
|
||||||
|
r.Name,
|
||||||
|
fullName = r.Region.Name + "/" + r.Name,
|
||||||
|
}).ToList();
|
||||||
|
return Ok(data);
|
||||||
|
}
|
||||||
|
public string GetFullBedName(Guid bedUuid)
|
||||||
|
{
|
||||||
|
var bed = _db.RegionRoomBed.Find(bedUuid);
|
||||||
|
if (bed == null)
|
||||||
|
return "";
|
||||||
|
var name = bed.Name;
|
||||||
|
var room = bed.Room;
|
||||||
|
if (room == null)
|
||||||
|
return name;
|
||||||
|
name = room.Name + "/" + name;
|
||||||
|
|
||||||
|
var region = room?.Region;
|
||||||
|
while (region != null)
|
||||||
|
{
|
||||||
|
name = region.Name + "/" + name;
|
||||||
|
region = region.Region2; // 遞迴向上
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
bool IsRegionOrAncestor(Model.Room room, Guid regionUuid)
|
||||||
|
{
|
||||||
|
//判斷傳入的regionuuid是否是room的祖先
|
||||||
|
if (room.RegionUuid == regionUuid)
|
||||||
|
return true;
|
||||||
|
var region = room.Region;
|
||||||
|
while (region != null)
|
||||||
|
{
|
||||||
|
if (region.Uuid == regionUuid) return true;
|
||||||
|
region = region.Region2;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public class UuidModel
|
||||||
|
{
|
||||||
|
public Guid? regionUuid = null;
|
||||||
|
public Guid? roomUuid = null;
|
||||||
|
public Guid? bedUuid = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,9 +74,11 @@ public class ShuWenController : ApiController
|
|||||||
{
|
{
|
||||||
shuwen.ShuWenList = ProcessDesserts2(_db.pro_order_detail.Where(a => a.pro_order.activity_num == activitynum.Value).ToList());
|
shuwen.ShuWenList = ProcessDesserts2(_db.pro_order_detail.Where(a => a.pro_order.activity_num == activitynum.Value).ToList());
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
shuwen.IsGenerating = false;
|
||||||
|
_db.SaveChanges();
|
||||||
|
return BadRequest("生成舒文失败:" + ex.Message);
|
||||||
}
|
}
|
||||||
shuwen.IsGenerating = false;
|
shuwen.IsGenerating = false;
|
||||||
shuwen.UpdateTime = DateTime.Now;
|
shuwen.UpdateTime = DateTime.Now;
|
||||||
@@ -222,34 +224,42 @@ public class ShuWenController : ApiController
|
|||||||
[Route("api/shuwen/download")]
|
[Route("api/shuwen/download")]
|
||||||
public HttpResponseMessage DownloadShuWenWord(int? activitynum)
|
public HttpResponseMessage DownloadShuWenWord(int? activitynum)
|
||||||
{
|
{
|
||||||
var data = _db.ShuWen.Where(a => a.ActivityNum == activitynum).FirstOrDefault();
|
try
|
||||||
if (data == null)
|
|
||||||
{
|
{
|
||||||
//return;
|
var data = _db.ShuWen.Where(a => a.ActivityNum == activitynum).FirstOrDefault();
|
||||||
}
|
if (data == null)
|
||||||
string json = data.ShuWenList;
|
|
||||||
string ActivityName = _db.activities.Where(a => a.num == data.ActivityNum).FirstOrDefault().subject;
|
|
||||||
if (json == null)
|
|
||||||
{
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
string fileName = $"疏文名單_{DateTime.Now:yyyyMMddHHmmss}.docx";
|
|
||||||
|
|
||||||
var stream = new MemoryStream();
|
|
||||||
GenerateShuWenWord_OpenXml(json, stream, ActivityName);
|
|
||||||
stream.Position = 0;
|
|
||||||
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
Content = new StreamContent(stream)
|
|
||||||
};
|
|
||||||
response.Content.Headers.ContentType =
|
|
||||||
new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
|
||||||
response.Content.Headers.ContentDisposition =
|
|
||||||
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
|
|
||||||
{
|
{
|
||||||
FileName = fileName
|
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "活動編號不能為空");
|
||||||
|
}
|
||||||
|
string json = data.ShuWenList;
|
||||||
|
string ActivityName = _db.activities.Where(a => a.num == data.ActivityNum).FirstOrDefault().subject;
|
||||||
|
if (json == null)
|
||||||
|
{
|
||||||
|
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "疏文列表为空,无法生成 Word");
|
||||||
|
}
|
||||||
|
string fileName = $"疏文名單_{DateTime.Now:yyyyMMddHHmmss}.docx";
|
||||||
|
|
||||||
|
var stream = new MemoryStream();
|
||||||
|
GenerateShuWenWord_OpenXml(json, stream, ActivityName);
|
||||||
|
stream.Position = 0;
|
||||||
|
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
Content = new StreamContent(stream)
|
||||||
};
|
};
|
||||||
return response;
|
response.Content.Headers.ContentType =
|
||||||
|
new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
||||||
|
response.Content.Headers.ContentDisposition =
|
||||||
|
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
|
||||||
|
{
|
||||||
|
FileName = fileName
|
||||||
|
};
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GenerateShuWenWord_OpenXml(string json, Stream outputStream, string ActivityName ="")
|
public void GenerateShuWenWord_OpenXml(string json, Stream outputStream, string ActivityName ="")
|
||||||
|
|||||||
140
web/App_Code/api/guadanGuestQueryController.cs
Normal file
140
web/App_Code/api/guadanGuestQueryController.cs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
using Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Entity;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Http;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// guadanGuestQueryController 的摘要描述
|
||||||
|
/// </summary>
|
||||||
|
public class guadanGuestQueryController: ApiController
|
||||||
|
{
|
||||||
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
|
public guadanGuestQueryController()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// TODO: 在這裡新增建構函式邏輯
|
||||||
|
//
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/guadan/guest/query/list")]
|
||||||
|
public async Task<IHttpActionResult> GetList([FromBody] SearchGuestModel search)
|
||||||
|
{
|
||||||
|
var query = _db.GuaDanOrderGuest
|
||||||
|
.Where(guest => guest.StatusCode != "404");
|
||||||
|
if(search.SearchName != null)
|
||||||
|
{
|
||||||
|
query = query.Where(guest => guest.followers.u_name.Contains(search.SearchName));
|
||||||
|
}
|
||||||
|
if(search.searchCheckInDate != null)
|
||||||
|
{
|
||||||
|
query = query.Where(guest => guest.CheckInAt == search.searchCheckInDate);
|
||||||
|
}
|
||||||
|
if(search.searchCheckOutDate != null)
|
||||||
|
{
|
||||||
|
query = query.Where(guest => guest.CheckOutAt == search.searchCheckOutDate);
|
||||||
|
}
|
||||||
|
if(search.searchCheckInDateStart != null)
|
||||||
|
{
|
||||||
|
query = query.Where(guest => guest.CheckInAt >= search.searchCheckInDateStart);
|
||||||
|
}
|
||||||
|
if (search.searchCheckInDateEnd != null)
|
||||||
|
{
|
||||||
|
query = query.Where(guest => guest.CheckInAt <= search.searchCheckInDateEnd);
|
||||||
|
}
|
||||||
|
if (search.searchCheckOutDateStart != null)
|
||||||
|
{
|
||||||
|
query = query.Where(guest => guest.CheckOutAt >= search.searchCheckOutDateStart);
|
||||||
|
}
|
||||||
|
if (search.searchCheckOutDateEnd != null)
|
||||||
|
{
|
||||||
|
query = query.Where(guest => guest.CheckOutAt <= search.searchCheckOutDateEnd);
|
||||||
|
}
|
||||||
|
var totalCount = await query.CountAsync();
|
||||||
|
var pagedData = await query
|
||||||
|
.OrderByDescending(a => a.CheckInAt) // 可根据需要排序
|
||||||
|
.Skip((search.Page - 1) * search.PageSize)
|
||||||
|
.Take(search.PageSize)
|
||||||
|
.ToListAsync();
|
||||||
|
var data1 = pagedData.Select(a => new
|
||||||
|
{
|
||||||
|
name = a.followers != null ? a.followers.u_name : null,
|
||||||
|
checkindate = a.CheckInAt,
|
||||||
|
checkoutdate = a.CheckOutAt,
|
||||||
|
guadanorderno = a.GuaDanOrderNo,
|
||||||
|
roomName = GetRoomAndBedString(a.RegionRoomBed),
|
||||||
|
statusName = a.RegionRoomBedStatus.Name
|
||||||
|
}).ToList();
|
||||||
|
return Ok(new
|
||||||
|
{
|
||||||
|
items = data1,
|
||||||
|
total = totalCount,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/guadan/guest/checkin/list")]
|
||||||
|
public async Task<IHttpActionResult> GetCheckInGuest([FromUri] DateTime date)
|
||||||
|
{
|
||||||
|
var today = DateTime.Now.Date;
|
||||||
|
var data = await _db.GuaDanOrderGuest
|
||||||
|
.Where(guest => guest.StatusCode == "402" || guest.StatusCode == "403")
|
||||||
|
.Where(guest => guest.RegionAndRoomAndBedSchedule
|
||||||
|
.Any(s => s.ScheduleDate == date.Date && s.ScheduleDate <= today) == true)
|
||||||
|
.Select(guest => new
|
||||||
|
{
|
||||||
|
name = guest.followers.u_name,
|
||||||
|
gender = guest.followers.sex,
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
return Ok(data);
|
||||||
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/guadan/guest/booking/list")]
|
||||||
|
public async Task<IHttpActionResult> GetBookingGuest([FromUri] DateTime date)
|
||||||
|
{
|
||||||
|
var data = await _db.GuaDanOrderGuest
|
||||||
|
.Where(guest => guest.StatusCode == "402" || guest.StatusCode == "401" || guest.StatusCode == "403")
|
||||||
|
.Where(guest => guest.RegionAndRoomAndBedSchedule.Any(s => s.ScheduleDate == date.Date) == true)
|
||||||
|
.Select(guest => new
|
||||||
|
{
|
||||||
|
name = guest.followers.u_name,
|
||||||
|
gender = guest.followers.sex,
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
return Ok(data);
|
||||||
|
}
|
||||||
|
public string GetRoomAndBedString(RegionRoomBed bed)
|
||||||
|
{
|
||||||
|
if (bed == null || bed.Room == null) return "";
|
||||||
|
var room = bed.Room;
|
||||||
|
var region = room.Region;
|
||||||
|
var name = room.Name + "/" + bed.Name;
|
||||||
|
if(region != null)
|
||||||
|
{
|
||||||
|
name = region.Name + "/" + name;
|
||||||
|
}
|
||||||
|
var parentRegion = region.Region2;
|
||||||
|
while (parentRegion != null)
|
||||||
|
{
|
||||||
|
name = parentRegion.Name + "/" + name;
|
||||||
|
parentRegion = parentRegion.Region2;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public class SearchGuestModel
|
||||||
|
{
|
||||||
|
public string SearchName = null;
|
||||||
|
public int Page = 1;
|
||||||
|
public int PageSize = 10;
|
||||||
|
public DateTime? searchCheckInDateStart = null;//入住日期的开始
|
||||||
|
public DateTime? searchCheckInDateEnd = null;//入住日期的结束
|
||||||
|
public DateTime? searchCheckOutDateStart = null;//退房日期的开始
|
||||||
|
public DateTime? searchCheckOutDateEnd = null;//退房日期的结束
|
||||||
|
public DateTime? searchCheckInDate = null;
|
||||||
|
public DateTime? searchCheckOutDate = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Model;
|
using Model;
|
||||||
|
using PagedList;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.Entity;
|
using System.Data.Entity;
|
||||||
@@ -12,14 +13,50 @@ using static regionController;
|
|||||||
/// guadanOderController 的摘要描述
|
/// guadanOderController 的摘要描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ezAuthorize]
|
[ezAuthorize]
|
||||||
public class guadanOrderController: ApiController
|
public class guadanOrderController : ApiController
|
||||||
{
|
{
|
||||||
private Model.ezEntities _db = new Model.ezEntities();
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
[HttpGet]
|
[HttpPost]
|
||||||
[Route("api/guadan/list")]
|
[Route("api/guadan/list")]
|
||||||
public async Task<IHttpActionResult> getGuadanList()
|
public async Task<IHttpActionResult> getGuadanList([FromBody] guadan_order_search_dto search)
|
||||||
{
|
{
|
||||||
var data = await _db.GuaDanOrder.OrderByDescending(b => b.CreatedAt)
|
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);
|
||||||
|
}
|
||||||
|
if (search.startDate != null && search.endDate != null)
|
||||||
|
{
|
||||||
|
query = query.Where(order => order.StartDate >= search.startDate)
|
||||||
|
.Where(order => order.EndDate <= search.endDate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (search.startDate != null)
|
||||||
|
{
|
||||||
|
query = query.Where(order => order.StartDate == search.startDate);
|
||||||
|
}
|
||||||
|
else if (search.endDate != null)
|
||||||
|
{
|
||||||
|
query = query.Where(order => order.EndDate == search.endDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var total = query.Count();
|
||||||
|
var data1 = await query.ToListAsync();
|
||||||
|
var data = data1
|
||||||
|
.OrderByDescending(b => b.CreatedAt)
|
||||||
.Select(a => new
|
.Select(a => new
|
||||||
{
|
{
|
||||||
uuid = a.Uuid,
|
uuid = a.Uuid,
|
||||||
@@ -29,24 +66,65 @@ public class guadanOrderController: ApiController
|
|||||||
created_at = a.CreatedAt,
|
created_at = a.CreatedAt,
|
||||||
updated_at = a.UpdatedAt,
|
updated_at = a.UpdatedAt,
|
||||||
notes = a.Notes,
|
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
|
||||||
|
{
|
||||||
|
subject = act.subject
|
||||||
|
})
|
||||||
|
.FirstOrDefault(),
|
||||||
bookerName = a.BookerName,
|
bookerName = a.BookerName,
|
||||||
guest_count = _db.GuaDanOrderGuest.Where(c => c.GuaDanOrderNo == a.GuaDanOrderNo).Count(),
|
guest_count = _db.GuaDanOrderGuest
|
||||||
}).ToListAsync();
|
.Where(c => c.GuaDanOrderNo == a.GuaDanOrderNo && c.IsDeleted == false)
|
||||||
return Ok(data);
|
.Where(c => c.RegionRoomBedStatus.Code != GuaDanOrderGuest.STATUS_CANCELLED)
|
||||||
|
.Count(),
|
||||||
|
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") ? 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") ? 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) ? new { code = 503, name = "正在入住" } :
|
||||||
|
new { code = 504, name = "部分退房" }
|
||||||
|
})
|
||||||
|
.Skip((search.page - 1) * search.pageSize)
|
||||||
|
.Take(search.pageSize)
|
||||||
|
.ToList();
|
||||||
|
return Ok(new
|
||||||
|
{
|
||||||
|
total,
|
||||||
|
data
|
||||||
|
});
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("api/guadan/getorderbyid")]
|
[Route("api/guadan/getorderbyid")]
|
||||||
public async Task<IHttpActionResult> getGuadanOrderById(string orderId)
|
public async Task<IHttpActionResult> getGuadanOrderById(string orderId)
|
||||||
{
|
{
|
||||||
var order = await _db.GuaDanOrder.Where(a => a.GuaDanOrderNo == orderId).FirstOrDefaultAsync();
|
var order = await _db.GuaDanOrder
|
||||||
|
.Where(a => a.GuaDanOrderNo == orderId)
|
||||||
|
.Where(a => a.IsCancel == false && a.IsDeleted == false)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
if (order == null)
|
if (order == null)
|
||||||
{
|
{
|
||||||
return BadRequest("未找到对应订单");
|
return BadRequest("未找到對應訂單");
|
||||||
}
|
}
|
||||||
var result = new
|
var result = new
|
||||||
{
|
{
|
||||||
order.admin,
|
order.admin,
|
||||||
order.follower,
|
order.followers,
|
||||||
StartDate = order.StartDate?.ToString("yyyy-MM-dd"),
|
StartDate = order.StartDate?.ToString("yyyy-MM-dd"),
|
||||||
EndDate = order.EndDate?.ToString("yyyy-MM-dd"),
|
EndDate = order.EndDate?.ToString("yyyy-MM-dd"),
|
||||||
order.CreateUser,
|
order.CreateUser,
|
||||||
@@ -59,6 +137,8 @@ public class guadanOrderController: ApiController
|
|||||||
order.BookerPhone,
|
order.BookerPhone,
|
||||||
order.IsDeleted,
|
order.IsDeleted,
|
||||||
order.Uuid,
|
order.Uuid,
|
||||||
|
order.ActivityNum,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
@@ -71,9 +151,9 @@ public class guadanOrderController: ApiController
|
|||||||
{
|
{
|
||||||
return BadRequest("掛單資料不可為空");
|
return BadRequest("掛單資料不可為空");
|
||||||
}
|
}
|
||||||
if(model.Uuid.HasValue)
|
if (model.Uuid.HasValue)
|
||||||
{
|
{
|
||||||
return BadRequest("已存在对应挂单资料");
|
return BadRequest("已存在對應掛單資料");
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -99,6 +179,7 @@ public class guadanOrderController: ApiController
|
|||||||
BookerName = model.bookerName,
|
BookerName = model.bookerName,
|
||||||
BookerPhone = model.bookerPhone,
|
BookerPhone = model.bookerPhone,
|
||||||
Uuid = Guid.NewGuid(),
|
Uuid = Guid.NewGuid(),
|
||||||
|
ActivityNum = model.activityNum,
|
||||||
};
|
};
|
||||||
_db.GuaDanOrder.Add(guadanorder);
|
_db.GuaDanOrder.Add(guadanorder);
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
@@ -131,26 +212,30 @@ public class guadanOrderController: ApiController
|
|||||||
var order = await _db.GuaDanOrder.FindAsync(model.Uuid.Value);
|
var order = await _db.GuaDanOrder.FindAsync(model.Uuid.Value);
|
||||||
if (order == null)
|
if (order == null)
|
||||||
{
|
{
|
||||||
return BadRequest("未找到对应挂单资料");
|
return BadRequest("未找到對應掛單資料");
|
||||||
}
|
}
|
||||||
order.StartDate = model.startdate;
|
order.StartDate = model.startdate;
|
||||||
order.EndDate = model.enddate;
|
order.EndDate = model.enddate;
|
||||||
order.Notes = model.note;
|
order.Notes = model.note;
|
||||||
order.BookerName = model.bookerName;
|
order.BookerName = model.bookerName;
|
||||||
order.BookerPhone = model.bookerPhone;
|
order.BookerPhone = model.bookerPhone;
|
||||||
|
order.ActivityNum = model.activityNum;
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
return Ok(model);
|
return Ok(model);
|
||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/guadan/delete")]
|
[Route("api/guadan/cancel")]
|
||||||
public async Task<IHttpActionResult> deleteGuadanOrder([FromUri] Guid uuid)
|
public async Task<IHttpActionResult> CancelGuadanOrder([FromUri] Guid uuid)
|
||||||
{
|
{
|
||||||
var guadan = await _db.GuaDanOrder.FindAsync(uuid);
|
var guadan = await _db.GuaDanOrder.FindAsync(uuid);
|
||||||
if (guadan == null)
|
if (guadan == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
if (_db.GuaDanOrderGuest.Any(a => (a.GuaDanOrderNo == guadan.GuaDanOrderNo) && a.StatusCode != "404"))
|
||||||
|
{
|
||||||
|
return BadRequest($"該掛單已經存在掛單蓮友,不能取消!");
|
||||||
|
}
|
||||||
using (var transaction = _db.Database.BeginTransaction())
|
using (var transaction = _db.Database.BeginTransaction())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -158,31 +243,27 @@ public class guadanOrderController: ApiController
|
|||||||
var guadanGuests = await _db.GuaDanOrderGuest
|
var guadanGuests = await _db.GuaDanOrderGuest
|
||||||
.Where(a => a.GuaDanOrderNo == guadan.GuaDanOrderNo)
|
.Where(a => a.GuaDanOrderNo == guadan.GuaDanOrderNo)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
var scheduleIds = _db.RegionAndRoomAndBedSchedule
|
|
||||||
.Where(a => a.GuaDanOrderNo == guadan.GuaDanOrderNo)
|
|
||||||
.Where( b => b.IsActive == true)
|
|
||||||
.Select(c => c.GuaDanOrderNo)
|
|
||||||
.ToList();
|
|
||||||
if (guadanGuests.Any())
|
if (guadanGuests.Any())
|
||||||
{
|
{
|
||||||
_db.GuaDanOrderGuest.RemoveRange(guadanGuests);
|
foreach (var guest in guadanGuests)
|
||||||
|
{
|
||||||
|
guest.StatusCode = "404";
|
||||||
|
// 取消所有相關的排程
|
||||||
|
if (guest.RegionAndRoomAndBedSchedule != null && guest.RegionAndRoomAndBedSchedule.Any())
|
||||||
|
{
|
||||||
|
foreach (var schedule in guest.RegionAndRoomAndBedSchedule)
|
||||||
|
{
|
||||||
|
schedule.IsCancel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
guadan.IsCancel = true;
|
||||||
if (scheduleIds.Any())
|
|
||||||
{
|
|
||||||
var schedules = await _db.RegionAndRoomAndBedSchedule
|
|
||||||
.Where(a => scheduleIds.Contains(a.GuaDanOrderNo))
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
if (schedules.Any())
|
|
||||||
_db.RegionAndRoomAndBedSchedule.RemoveRange(schedules);
|
|
||||||
}
|
|
||||||
_db.GuaDanOrder.Remove(guadan);
|
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
|
|
||||||
return Ok(new { message = "删除成功" });
|
return Ok(new { message = "取消成功" });
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -200,7 +281,6 @@ public class guadanOrderController: ApiController
|
|||||||
public int guest_id { get; set; }
|
public int guest_id { get; set; }
|
||||||
public DateTime start_date { get; set; }
|
public DateTime start_date { get; set; }
|
||||||
public DateTime? end_date { get; set; }
|
public DateTime? end_date { get; set; }
|
||||||
public Guid? statusUuid { get; set; }
|
|
||||||
public int? create_user { get; set; }
|
public int? create_user { get; set; }
|
||||||
public DateTime created_at { get; set; }
|
public DateTime created_at { get; set; }
|
||||||
public DateTime updated_at { get; set; }
|
public DateTime updated_at { get; set; }
|
||||||
@@ -211,4 +291,14 @@ public class guadanOrderController: ApiController
|
|||||||
public RegionRoomBed bed { get; set; } = null;
|
public RegionRoomBed bed { get; set; } = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class guadan_order_search_dto
|
||||||
|
{
|
||||||
|
public DateTime? startDate { get; set; }
|
||||||
|
public DateTime? endDate { get; set; }
|
||||||
|
public string guadanUser { get; set; }
|
||||||
|
public int page { get; set; } = 1;
|
||||||
|
public int pageSize { get; set; } = 10;
|
||||||
|
public string guaDanOrderNo { get; set; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
using Model;
|
using DocumentFormat.OpenXml.Drawing;
|
||||||
|
using Model;
|
||||||
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.Entity;
|
using System.Data.Entity;
|
||||||
|
using System.Data.Entity.Infrastructure;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using System.Web.Http;
|
using System.Web.Http;
|
||||||
@@ -11,7 +15,7 @@ using System.Web.Http;
|
|||||||
/// guadanOrderGuest 的摘要描述
|
/// guadanOrderGuest 的摘要描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ezAuthorize]
|
[ezAuthorize]
|
||||||
public class guadanOrderGuestController: ApiController
|
public class guadanOrderGuestController : ApiController
|
||||||
{
|
{
|
||||||
private Model.ezEntities _db = new Model.ezEntities();
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -25,12 +29,12 @@ public class guadanOrderGuestController: ApiController
|
|||||||
[Route("api/guadanorderguest/getbyorderno")]
|
[Route("api/guadanorderguest/getbyorderno")]
|
||||||
public async Task<IHttpActionResult> getByOrderNo(string orderNo)
|
public async Task<IHttpActionResult> getByOrderNo(string orderNo)
|
||||||
{
|
{
|
||||||
// 先查数据库,不做格式化
|
// 先查資料庫,不做格式化
|
||||||
var qry = await _db.GuaDanOrderGuest
|
var qry = await _db.GuaDanOrderGuest
|
||||||
.Where(a => a.GuaDanOrderNo == orderNo && a.IsDeleted == false)
|
.Where(a => a.GuaDanOrderNo == orderNo && a.IsDeleted == false && a.RegionRoomBedStatus.Code != "404")
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
// 拉到内存后再处理日期
|
// 拉到記憶體後再處理日期
|
||||||
var data = qry.Select(a => new guadan_order_guest_display_dto
|
var data = qry.Select(a => new guadan_order_guest_display_dto
|
||||||
{
|
{
|
||||||
Uuid = a.Uuid,
|
Uuid = a.Uuid,
|
||||||
@@ -42,27 +46,50 @@ public class guadanOrderGuestController: ApiController
|
|||||||
checkoutat = a.CheckOutAt.HasValue ? a.CheckOutAt.Value.ToString("yyyy-MM-dd") : null,
|
checkoutat = a.CheckOutAt.HasValue ? a.CheckOutAt.Value.ToString("yyyy-MM-dd") : null,
|
||||||
phone = null,
|
phone = null,
|
||||||
roomName = a.Room.Name,
|
roomName = a.Room.Name,
|
||||||
bedName = a.RegionRoomBed.Name,
|
bedName = GetBedString(a.RegionRoomBed),
|
||||||
orderNo = a.GuaDanOrderNo,
|
orderNo = a.GuaDanOrderNo,
|
||||||
follower = a.follower,
|
follower = a.followers == null ? null : new FollowerDto
|
||||||
statusUuid = a.statusUuid,
|
{
|
||||||
|
num = a.followers.num,
|
||||||
|
u_name = a.followers.u_name,
|
||||||
|
sex = a.followers.sex
|
||||||
|
},
|
||||||
|
statuscode = a.StatusCode,
|
||||||
statusName = a.RegionRoomBedStatus?.Name,
|
statusName = a.RegionRoomBedStatus?.Name,
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
}
|
}
|
||||||
|
public string GetBedString(RegionRoomBed bed)
|
||||||
|
{
|
||||||
|
if (bed == null)
|
||||||
|
return "";
|
||||||
|
var room = bed.Room;
|
||||||
|
var name = room.Name + "/" + bed.Name;
|
||||||
|
var region = room.Region;
|
||||||
|
name = region.Name + "/" + name;
|
||||||
|
var parentRegion = region.Region2;
|
||||||
|
while(parentRegion != null)
|
||||||
|
{
|
||||||
|
name = parentRegion.Name + "/" + name;
|
||||||
|
parentRegion = parentRegion.Region2;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/guadanorderguest/create")]
|
[Route("api/guadanorderguest/create")]
|
||||||
public async Task<IHttpActionResult> create([FromBody] guadan_order_guest_dto model)
|
public async Task<IHttpActionResult> create([FromBody] guadan_order_guest_dto model)
|
||||||
{
|
{
|
||||||
if (model == null)
|
if (model == null)
|
||||||
return BadRequest("");
|
return BadRequest("");
|
||||||
|
/*if(model.statuscode == null)
|
||||||
|
{
|
||||||
|
return BadRequest("狀態不能為空");
|
||||||
|
}*/
|
||||||
// 驗證床位與蓮友
|
// 驗證床位與蓮友
|
||||||
|
var bed = _db.RegionRoomBed.Find(model.bedUuid.Value);
|
||||||
if (model.followerNum.HasValue && model.bedUuid.HasValue)
|
if (model.followerNum.HasValue && model.bedUuid.HasValue)
|
||||||
{
|
{
|
||||||
var bed = _db.RegionRoomBed.Find(model.bedUuid.Value);
|
|
||||||
var follower = _db.followers.Find(model.followerNum.Value);
|
var follower = _db.followers.Find(model.followerNum.Value);
|
||||||
|
|
||||||
if (bed == null || follower == null)
|
if (bed == null || follower == null)
|
||||||
@@ -81,16 +108,16 @@ public class guadanOrderGuestController: ApiController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!model.bedUuid.HasValue)
|
if (!model.bedUuid.HasValue)
|
||||||
return BadRequest("床位 UUID 不能为空");
|
return BadRequest("床位 UUID 不能為空");
|
||||||
if (!model.checkInAt.HasValue)
|
if (!model.checkInAt.HasValue)
|
||||||
return BadRequest("入住时间不能为空");
|
return BadRequest("入住時間不能為空");
|
||||||
|
|
||||||
// 長期占用處理:checkOutAt 可為 null
|
// 長期占用處理:checkOutAt 可為 null
|
||||||
DateTime? checkOut = model.checkOutAt.Value.Date;
|
DateTime? checkOut = model.checkOutAt.Value.Date;
|
||||||
|
|
||||||
if (checkOut.HasValue && model.checkInAt > checkOut)
|
if (checkOut.HasValue && model.checkInAt > checkOut)
|
||||||
return BadRequest("掛單結束時間不能再開始時間之前");
|
return BadRequest("掛單結束時間不能再開始時間之前");
|
||||||
if(model.checkInAt == model.checkOutAt)
|
if (model.checkInAt == model.checkOutAt)
|
||||||
{
|
{
|
||||||
return BadRequest("掛單結束時間和開始時間不能是同一天");
|
return BadRequest("掛單結束時間和開始時間不能是同一天");
|
||||||
}
|
}
|
||||||
@@ -103,8 +130,22 @@ public class guadanOrderGuestController: ApiController
|
|||||||
);
|
);
|
||||||
if (!bedIsCanUse)
|
if (!bedIsCanUse)
|
||||||
return BadRequest("床位在該時間段內已被占用");
|
return BadRequest("床位在該時間段內已被占用");
|
||||||
|
if (model.followerNum.HasValue)
|
||||||
|
{
|
||||||
|
if (_db.GuaDanOrderGuest.Any(a => a.FollowerNum == model.followerNum
|
||||||
|
&& a.GuaDanOrderNo == model.orderNo
|
||||||
|
&& a.StatusCode != "404"
|
||||||
|
))
|
||||||
|
return BadRequest("該蓮友已經在該掛單中");
|
||||||
|
}
|
||||||
|
//建立訂單的的時候,狀態只能是401或者402
|
||||||
|
var targetStatus = _db.RegionRoomBedStatus.Where(a => a.Code == GuaDanOrderGuest.STATUS_BOOKED).FirstOrDefault();
|
||||||
|
|
||||||
|
if (targetStatus == null)
|
||||||
|
{
|
||||||
|
return Content(HttpStatusCode.PreconditionFailed, "找不到目標狀態,請先建立對應狀態");
|
||||||
|
}
|
||||||
|
|
||||||
// 建立掛單
|
|
||||||
var guest = new GuaDanOrderGuest
|
var guest = new GuaDanOrderGuest
|
||||||
{
|
{
|
||||||
GuaDanOrderNo = model.orderNo,
|
GuaDanOrderNo = model.orderNo,
|
||||||
@@ -114,14 +155,9 @@ public class guadanOrderGuestController: ApiController
|
|||||||
CheckInAt = model.checkInAt?.Date,
|
CheckInAt = model.checkInAt?.Date,
|
||||||
CheckOutAt = checkOut,
|
CheckOutAt = checkOut,
|
||||||
Uuid = Guid.NewGuid(),
|
Uuid = Guid.NewGuid(),
|
||||||
statusUuid = model.statusUuid,
|
StatusCode = GuaDanOrderGuest.STATUS_BOOKED,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (model.followerNum.HasValue)
|
|
||||||
{
|
|
||||||
if (_db.GuaDanOrderGuest.Any(a => a.FollowerNum == model.followerNum && a.GuaDanOrderNo == model.orderNo))
|
|
||||||
return BadRequest("該蓮友已經在該掛單中");
|
|
||||||
}
|
|
||||||
|
|
||||||
_db.GuaDanOrderGuest.Add(guest);
|
_db.GuaDanOrderGuest.Add(guest);
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
@@ -140,12 +176,13 @@ public class guadanOrderGuestController: ApiController
|
|||||||
Description = "床位掛單",
|
Description = "床位掛單",
|
||||||
ScheduleDate = scheduleDate,
|
ScheduleDate = scheduleDate,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
IsActive = true,
|
IsCancel = false,
|
||||||
TargetUuid = guest.BedUuid,
|
TargetUuid = guest.BedUuid,
|
||||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.Now,
|
||||||
GuaDanOrderNo = guest.GuaDanOrderNo,
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||||
Uuid = Guid.NewGuid()
|
Uuid = Guid.NewGuid(),
|
||||||
|
GuaDanOrderGuestUuid = guest.Uuid,
|
||||||
};
|
};
|
||||||
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
||||||
}
|
}
|
||||||
@@ -159,19 +196,17 @@ public class guadanOrderGuestController: ApiController
|
|||||||
Description = "床位掛單(長期占用)",
|
Description = "床位掛單(長期占用)",
|
||||||
ScheduleDate = null,
|
ScheduleDate = null,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
IsActive = true,
|
IsCancel = false,
|
||||||
TargetUuid = guest.BedUuid,
|
TargetUuid = guest.BedUuid,
|
||||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.Now,
|
||||||
GuaDanOrderNo = guest.GuaDanOrderNo,
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||||
Uuid = Guid.NewGuid()
|
Uuid = Guid.NewGuid(),
|
||||||
|
GuaDanOrderGuestUuid = guest.Uuid
|
||||||
};
|
};
|
||||||
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,10 +236,10 @@ public class guadanOrderGuestController: ApiController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!model.bedUuid.HasValue)
|
if (!model.bedUuid.HasValue)
|
||||||
return BadRequest("床位 UUID 不能为空");
|
return BadRequest("床位 UUID 不能為空");
|
||||||
|
|
||||||
if (!model.checkInAt.HasValue)
|
if (!model.checkInAt.HasValue)
|
||||||
return BadRequest("入住时间不能为空");
|
return BadRequest("入住時間不能為空");
|
||||||
|
|
||||||
// 長期占用處理
|
// 長期占用處理
|
||||||
DateTime? checkOut = model.checkOutAt?.Date;
|
DateTime? checkOut = model.checkOutAt?.Date;
|
||||||
@@ -234,18 +269,27 @@ public class guadanOrderGuestController: ApiController
|
|||||||
.AnyAsync();
|
.AnyAsync();
|
||||||
if (exists) return BadRequest("該蓮友已經在該掛單中");
|
if (exists) return BadRequest("該蓮友已經在該掛單中");
|
||||||
}
|
}
|
||||||
|
/*var targetStatus = _db.RegionRoomBedStatus.Find(model.statuscode);
|
||||||
|
if (targetStatus == null)
|
||||||
|
{
|
||||||
|
return BadRequest("目標狀態不存在");
|
||||||
|
}
|
||||||
|
if(!StatusTransitionManager.CanTransition(guest.StatusCode,targetStatus.Code))
|
||||||
|
{
|
||||||
|
return BadRequest("狀態的變化不合法");
|
||||||
|
}*/
|
||||||
// 更新掛單基本資料
|
// 更新掛單基本資料
|
||||||
guest.FollowerNum = model.followerNum;
|
guest.FollowerNum = model.followerNum;
|
||||||
guest.RoomUuid = model.roomUuid;
|
guest.RoomUuid = model.roomUuid;
|
||||||
guest.BedUuid = model.bedUuid;
|
guest.BedUuid = model.bedUuid;
|
||||||
guest.CheckInAt = model.checkInAt?.Date;
|
guest.CheckInAt = model.checkInAt?.Date;
|
||||||
guest.CheckOutAt = checkOut;
|
guest.CheckOutAt = checkOut;
|
||||||
guest.statusUuid = model.statusUuid;
|
//guest.StatusCode = model.statuscode;
|
||||||
|
//更新的時候不能更新狀態,狀態都用單獨的操作api控制
|
||||||
|
|
||||||
// 刪除原有每日排程
|
// 刪除原有每日排程
|
||||||
var oldSchedules = _db.RegionAndRoomAndBedSchedule
|
var oldSchedules = _db.RegionAndRoomAndBedSchedule
|
||||||
.Where(s => s.GuaDanOrderNo == guest.GuaDanOrderNo)
|
.Where(s => s.GuaDanOrderNo == guest.GuaDanOrderNo && s.TargetUuid == guest.BedUuid)
|
||||||
.ToList();
|
.ToList();
|
||||||
_db.RegionAndRoomAndBedSchedule.RemoveRange(oldSchedules);
|
_db.RegionAndRoomAndBedSchedule.RemoveRange(oldSchedules);
|
||||||
|
|
||||||
@@ -262,12 +306,13 @@ public class guadanOrderGuestController: ApiController
|
|||||||
Description = "床位掛單",
|
Description = "床位掛單",
|
||||||
ScheduleDate = date,
|
ScheduleDate = date,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
IsActive = true,
|
IsCancel = false,
|
||||||
TargetUuid = guest.BedUuid,
|
TargetUuid = guest.BedUuid,
|
||||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.Now,
|
||||||
GuaDanOrderNo = guest.GuaDanOrderNo,
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||||
Uuid = Guid.NewGuid()
|
Uuid = Guid.NewGuid(),
|
||||||
|
GuaDanOrderGuestUuid = guest.Uuid,
|
||||||
};
|
};
|
||||||
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
||||||
}
|
}
|
||||||
@@ -281,12 +326,13 @@ public class guadanOrderGuestController: ApiController
|
|||||||
Description = "床位掛單(長期占用)",
|
Description = "床位掛單(長期占用)",
|
||||||
ScheduleDate = null,
|
ScheduleDate = null,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
IsActive = true,
|
IsCancel = false,
|
||||||
TargetUuid = guest.BedUuid,
|
TargetUuid = guest.BedUuid,
|
||||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.Now,
|
||||||
GuaDanOrderNo = guest.GuaDanOrderNo,
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||||
Uuid = Guid.NewGuid()
|
Uuid = Guid.NewGuid(),
|
||||||
|
GuaDanOrderGuestUuid = guest.Uuid,
|
||||||
};
|
};
|
||||||
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
_db.RegionAndRoomAndBedSchedule.Add(schedul);
|
||||||
}
|
}
|
||||||
@@ -296,27 +342,293 @@ public class guadanOrderGuestController: ApiController
|
|||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/guadanorderguest/delete")]
|
[Route("api/guadanorderguest/xuzhu")]
|
||||||
public async Task<IHttpActionResult> deleteGuadanGuest([FromUri] Guid uuid)
|
public async Task<IHttpActionResult> ExtendStay([FromBody] XuZhuModel model)
|
||||||
|
{
|
||||||
|
//續住方法
|
||||||
|
if (model == null)
|
||||||
|
return BadRequest("請求數據為空");
|
||||||
|
|
||||||
|
if (model.GuestUuid == Guid.Empty || model.GuestBedUuid == Guid.Empty)
|
||||||
|
return BadRequest("GuestUuid 或 GuestBedUuid 無效");
|
||||||
|
var guest = await _db.GuaDanOrderGuest.FindAsync(model.GuestUuid);
|
||||||
|
if (guest == null)
|
||||||
|
{
|
||||||
|
return BadRequest("掛單不存在");
|
||||||
|
}
|
||||||
|
if (guest.BedUuid != model.GuestBedUuid)
|
||||||
|
{
|
||||||
|
return BadRequest("床位不正確");
|
||||||
|
}
|
||||||
|
var bedIsCanUse = await RegionAndRoomAndBedSchedule.IsBedAvailableAsync(_db, model.GuestBedUuid, model.CurrentCheckoutDate, model.NewCheckoutDate);
|
||||||
|
if (!bedIsCanUse)
|
||||||
|
{
|
||||||
|
return BadRequest("該床位在續住時間段內被預定,無法續住");
|
||||||
|
}
|
||||||
|
|
||||||
|
var newStartDate = model.CurrentCheckoutDate.Date;
|
||||||
|
var newEndDate = model.NewCheckoutDate.Date.AddDays(-1);
|
||||||
|
if (newEndDate < newStartDate)
|
||||||
|
return BadRequest("續住日期區間無效");
|
||||||
|
for (var date = newStartDate; date <= newEndDate; date = date.AddDays(1))
|
||||||
|
{
|
||||||
|
var newSchedule = new RegionAndRoomAndBedSchedule
|
||||||
|
{
|
||||||
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||||
|
Uuid = Guid.NewGuid(),
|
||||||
|
TargetUuid = model.GuestBedUuid,
|
||||||
|
GuaDanOrderGuestUuid = model.GuestUuid,
|
||||||
|
ScheduleDate = date,
|
||||||
|
Title = "續住掛單", // 一天一條,開始和結束是同一天
|
||||||
|
Description = "續住掛單",
|
||||||
|
UseType = 30,
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
|
||||||
|
_db.RegionAndRoomAndBedSchedule.Add(newSchedule);
|
||||||
|
}
|
||||||
|
guest.CheckOutAt = model.NewCheckoutDate.Date;
|
||||||
|
await _db.SaveChangesAsync(); // 保存資料庫操作
|
||||||
|
return Ok(new { message = "續住成功" });
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/guadanorderguest/cancel")]
|
||||||
|
public async Task<IHttpActionResult> CancelGuadanGuest([FromUri] Guid uuid)
|
||||||
{
|
{
|
||||||
var guest = await _db.GuaDanOrderGuest.FindAsync(uuid);
|
var guest = await _db.GuaDanOrderGuest.FindAsync(uuid);
|
||||||
if (guest == null)
|
if (guest == null)
|
||||||
return BadRequest("未找到指定挂单资料");
|
return NotFound();
|
||||||
|
|
||||||
// 删除所有与该 guest 相关的排程(每日排程或長期占用)
|
if (guest.StatusCode == "404")
|
||||||
var schedules = _db.RegionAndRoomAndBedSchedule
|
return BadRequest("該掛單已取消,無需再取消");
|
||||||
.Where(s => s.GuaDanOrderNo == guest.GuaDanOrderNo)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (schedules.Any())
|
if (!StatusTransitionManager.CanTransition(guest.StatusCode, "404"))
|
||||||
_db.RegionAndRoomAndBedSchedule.RemoveRange(schedules);
|
{
|
||||||
|
return BadRequest("當前狀態不能取消");
|
||||||
|
}
|
||||||
|
var cancelStatus = await _db.RegionRoomBedStatus
|
||||||
|
.FirstOrDefaultAsync(a => a.Code == "404");
|
||||||
|
if (cancelStatus == null)
|
||||||
|
return Content(HttpStatusCode.PreconditionFailed, "找不到取消狀態(Code=404),請先建立對應狀態");
|
||||||
|
//把狀態設置為取消
|
||||||
|
using (var tx = _db.Database.BeginTransaction())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1) 更新 guest
|
||||||
|
guest.StatusCode = "404";
|
||||||
|
|
||||||
_db.GuaDanOrderGuest.Remove(guest);
|
// 2) 取消相關排程(常見做法:只取消未來&未取消的)
|
||||||
await _db.SaveChangesAsync();
|
var today = DateTime.Today;
|
||||||
|
|
||||||
return Ok(new { message = "删除成功" });
|
var schedules = await _db.RegionAndRoomAndBedSchedule
|
||||||
|
.Where(s => s.GuaDanOrderGuestUuid == guest.Uuid
|
||||||
|
&& s.IsCancel == false
|
||||||
|
//&& s.ScheduleDate >= today
|
||||||
|
)
|
||||||
|
// ✅ 只取消今天與未來的,能取消就代表未入住,
|
||||||
|
// 未入住就要全部取消,如果是入住後提前退房,
|
||||||
|
// 就要取消未來的,取消未來的時候要注意今日是否包含的問題
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (var s in schedules)
|
||||||
|
{
|
||||||
|
s.IsCancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) 釋放占用資源(若有床位/房間占用紀錄)
|
||||||
|
if (guest.BedUuid != null)
|
||||||
|
{
|
||||||
|
// 先抓到目標狀態
|
||||||
|
var freeStatus = await _db.RegionRoomBedStatus
|
||||||
|
.FirstOrDefaultAsync(a => a.Code == "101");
|
||||||
|
|
||||||
|
if (freeStatus == null)
|
||||||
|
return Content(HttpStatusCode.PreconditionFailed, "找不到床位狀態 Code=101");
|
||||||
|
if (guest.RegionRoomBed != null)
|
||||||
|
{
|
||||||
|
guest.RegionRoomBed.StatusCode = freeStatus.Code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _db.SaveChangesAsync();
|
||||||
|
tx.Commit();
|
||||||
|
|
||||||
|
return Ok(new
|
||||||
|
{
|
||||||
|
message = "取消成功",
|
||||||
|
guestUuid = guest.Uuid,
|
||||||
|
canceledSchedules = schedules.Count
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (DbUpdateConcurrencyException)
|
||||||
|
{
|
||||||
|
tx.Rollback();
|
||||||
|
return StatusCode(HttpStatusCode.PreconditionFailed); // 或自訂訊息
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
tx.Rollback();
|
||||||
|
return InternalServerError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/guadanorderguest/checkout")]
|
||||||
|
public IHttpActionResult CheckoutGuadanOrderGuest(Guid uuid)
|
||||||
|
{
|
||||||
|
DbContextTransaction transaction = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
transaction = _db.Database.BeginTransaction(); // 開啟事務
|
||||||
|
|
||||||
|
// 1️⃣ 取得該筆掛單
|
||||||
|
var guest = _db.GuaDanOrderGuest
|
||||||
|
.Where(a => a.Uuid == uuid)
|
||||||
|
.Where(a => !a.IsDeleted && a.StatusCode != "404")
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (guest == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
// 2️⃣ 標記為已退房
|
||||||
|
var targetStatus = _db.RegionRoomBedStatus
|
||||||
|
.Where(a => a.Code == "403")
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (targetStatus == null)
|
||||||
|
return Content(HttpStatusCode.PreconditionFailed, "找不到退房狀態(Code=403),請先建立對應狀態");
|
||||||
|
|
||||||
|
if (!StatusTransitionManager.CanTransition(guest.StatusCode, targetStatus.Code))
|
||||||
|
return BadRequest("掛單狀態轉換不對");
|
||||||
|
|
||||||
|
if (!StatusTransitionManager.CanTransition(guest.RegionRoomBed.StatusCode, "101"))
|
||||||
|
return BadRequest("床位掛單狀態轉換不對");
|
||||||
|
|
||||||
|
guest.StatusCode = targetStatus.Code;
|
||||||
|
guest.RegionRoomBed.StatusCode = "101";
|
||||||
|
|
||||||
|
//更新未來排程為取消
|
||||||
|
var latestCheckoutStr = _db.GuadanTimeSetting
|
||||||
|
.Select(a => a.LatestCheckOut) // 字串 "HH:mm"
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
TimeSpan? latestCheckoutTime = null;
|
||||||
|
if (!string.IsNullOrEmpty(latestCheckoutStr))
|
||||||
|
{
|
||||||
|
// 嘗試解析字串
|
||||||
|
if (TimeSpan.TryParse(latestCheckoutStr, out var ts))
|
||||||
|
{
|
||||||
|
latestCheckoutTime = ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var futureSchedules = _db.RegionAndRoomAndBedSchedule
|
||||||
|
.Where(s => s.GuaDanOrderGuestUuid == guest.Uuid);
|
||||||
|
if (latestCheckoutTime == null || DateTime.Now.TimeOfDay > latestCheckoutTime)
|
||||||
|
{
|
||||||
|
// 包含今天
|
||||||
|
futureSchedules = futureSchedules.Where(s => s.ScheduleDate > DateTime.Today);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 不包含今天
|
||||||
|
futureSchedules = futureSchedules.Where(s => s.ScheduleDate >= DateTime.Today);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var schedule in futureSchedules)
|
||||||
|
{
|
||||||
|
schedule.IsCancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4️⃣ 保存所有變更
|
||||||
|
_db.SaveChanges();
|
||||||
|
|
||||||
|
// 5️⃣ 提交事務
|
||||||
|
transaction.Commit();
|
||||||
|
|
||||||
|
return Ok(new { message = "退房完成", guestUuid = guest.Uuid });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (transaction != null)
|
||||||
|
transaction.Rollback(); // 回滾事務
|
||||||
|
return InternalServerError(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (transaction != null)
|
||||||
|
transaction.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/guadanorderguest/checkin")]
|
||||||
|
public IHttpActionResult CheckinGuadanGuest([FromUri] Guid uuid)
|
||||||
|
{
|
||||||
|
if (uuid == Guid.Empty)
|
||||||
|
return BadRequest("uuid不能為空");
|
||||||
|
|
||||||
|
// 獲取掛單客人
|
||||||
|
var guest = _db.GuaDanOrderGuest
|
||||||
|
.Include(g => g.RegionRoomBedStatus) // 包含導航屬性
|
||||||
|
.FirstOrDefault(g => g.Uuid == uuid);
|
||||||
|
|
||||||
|
if (guest == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
string currentStatus = guest.StatusCode;
|
||||||
|
|
||||||
|
// 判斷狀態流轉是否合法
|
||||||
|
if (!StatusTransitionManager.CanTransition(currentStatus, GuaDanOrderGuest.STATUS_CHECKED_IN))
|
||||||
|
{
|
||||||
|
return BadRequest("當前狀態不允許入住");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 新增:檢查今天是否在排程表 ----------
|
||||||
|
var today = DateTime.Today;
|
||||||
|
bool hasScheduleToday = _db.RegionAndRoomAndBedSchedule
|
||||||
|
.Any(s => s.GuaDanOrderGuestUuid == guest.Uuid && s.ScheduleDate == today);
|
||||||
|
|
||||||
|
if (!hasScheduleToday)
|
||||||
|
{
|
||||||
|
return BadRequest("不在入住時間段內,無法入住");
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 更新狀態
|
||||||
|
guest.StatusCode = GuaDanOrderGuest.STATUS_CHECKED_IN;
|
||||||
|
|
||||||
|
// 如果需要,更新床位狀態,比如變為占用
|
||||||
|
if (guest.BedUuid != null)
|
||||||
|
{
|
||||||
|
var bed = _db.RegionRoomBed.FirstOrDefault(b => b.Uuid == guest.BedUuid);
|
||||||
|
if (bed == null)
|
||||||
|
{
|
||||||
|
return BadRequest("入住床位不存在");
|
||||||
|
}
|
||||||
|
if (StatusTransitionManager.CanTransition(bed.StatusCode, "102")) // 102 = 占用
|
||||||
|
{
|
||||||
|
bed.StatusCode = "102";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BadRequest($"當前床位狀態:{bed.RegionRoomBedStatus.Name} 不能入住");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (guest.BedUuid == null)
|
||||||
|
{
|
||||||
|
return BadRequest("入住床位不存在");
|
||||||
|
}
|
||||||
|
_db.SaveChanges();
|
||||||
|
|
||||||
|
return Ok(new { message = "入住成功", statusCode = guest.StatusCode });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return InternalServerError(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class guadan_order_guest_dto
|
public class guadan_order_guest_dto
|
||||||
@@ -328,7 +640,7 @@ public class guadanOrderGuestController: ApiController
|
|||||||
public Guid? bedUuid { get; set; }
|
public Guid? bedUuid { get; set; }
|
||||||
public DateTime? checkInAt { get; set; }
|
public DateTime? checkInAt { get; set; }
|
||||||
public DateTime? checkOutAt { get; set; }
|
public DateTime? checkOutAt { get; set; }
|
||||||
public Guid? statusUuid { get; set; }
|
public string statuscode { get; set; }
|
||||||
}
|
}
|
||||||
public class guadan_order_guest_display_dto
|
public class guadan_order_guest_display_dto
|
||||||
{
|
{
|
||||||
@@ -337,17 +649,31 @@ public class guadanOrderGuestController: ApiController
|
|||||||
public string orderNo { get; set; }
|
public string orderNo { get; set; }
|
||||||
public string name { get; set; }
|
public string name { get; set; }
|
||||||
public Guid? roomUuid { get; set; }
|
public Guid? roomUuid { get; set; }
|
||||||
public Guid? bedUuid { get;set; }
|
public Guid? bedUuid { get; set; }
|
||||||
public string checkinat { get;set; }
|
public string checkinat { get; set; }
|
||||||
public string checkoutat { get;set; }
|
public string checkoutat { get; set; }
|
||||||
public int? gender { get; set; }
|
public int? gender { get; set; }
|
||||||
public Guid? statusUuid { get; set; }
|
public string statuscode { get; set; }
|
||||||
public string statusName { get; set; }
|
public string statusName { get; set; }
|
||||||
public string phone { get; set; }
|
public string phone { get; set; }
|
||||||
public string note { get; set; }
|
public string note { get; set; }
|
||||||
public string roomName { get; set; }
|
public string roomName { get; set; }
|
||||||
public string bedName { get; set; }
|
public string bedName { get; set; }
|
||||||
public follower follower { get; set; }
|
public bool iscancel { get; set; }
|
||||||
|
public FollowerDto follower { get; set; }
|
||||||
|
}
|
||||||
|
public class FollowerDto
|
||||||
|
{
|
||||||
|
public int num { get; set; }
|
||||||
|
public string u_name { get; set; }
|
||||||
|
public string sex { get; set; }
|
||||||
|
}
|
||||||
|
public class XuZhuModel
|
||||||
|
{
|
||||||
|
public Guid GuestUuid { get; set; } // 不可為空
|
||||||
|
public Guid GuestBedUuid { get; set; } // 不可為空
|
||||||
|
public DateTime CurrentCheckoutDate { get; set; } // 當前退房時間
|
||||||
|
public DateTime NewCheckoutDate { get; set; } // 新退房時間
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -21,39 +21,49 @@ public class guadanStatisticsController: ApiController
|
|||||||
//挂单统计:房间,床位,挂单笔数,挂单人数的统计
|
//挂单统计:房间,床位,挂单笔数,挂单人数的统计
|
||||||
|
|
||||||
var now = DateTime.Now;
|
var now = DateTime.Now;
|
||||||
var roomCount = await _db.Room.Where(a => a.IsDeleted == false).CountAsync();
|
var guadanTotalCount = await _db.GuaDanOrder
|
||||||
var rooms = await _db.Room.Include(r => r.RegionRoomBed).ToListAsync();
|
.Where(a => a.IsDeleted == false)
|
||||||
|
.Where(a => a.IsCancel == false)
|
||||||
var emptyRoomCount = rooms
|
.CountAsync();
|
||||||
.Where(r => r.RegionRoomBed.All(b => b.IsAvailableDuring(now, now, _db))) // 這裡就能用方法
|
var guadanCurrentCount = await _db.GuaDanOrderGuest
|
||||||
.Count();
|
.Where(guest => guest.StatusCode != "403")
|
||||||
var bedCount = await _db.RegionRoomBed.Where(a => a.IsDeleted == false).CountAsync();
|
.Where(guest => guest.StatusCode != "404")
|
||||||
var maleBedCount = await _db.RegionRoomBed.Where(a => a.IsDeleted == false && a.Gender == true).CountAsync();
|
.Select(guest => guest.GuaDanOrderNo)
|
||||||
var femaleBedCount = await _db.RegionRoomBed.Where(a => a.IsDeleted == false && a.Gender == false).CountAsync();
|
.Distinct()
|
||||||
|
.CountAsync();
|
||||||
var guadanTotalCount = await _db.GuaDanOrder.Where(a => a.IsDeleted == false).CountAsync();
|
var guadanPeopleTotal = await _db.GuaDanOrderGuest
|
||||||
var guadanPeopleTotal = await _db.GuaDanOrderGuest.Where(a => a.IsDeleted == false).CountAsync();
|
.Where(a => a.IsDeleted == false)
|
||||||
var guadanPeopleMale = await _db.GuaDanOrderGuest.Where(a => a.IsDeleted == false && a.follower.sex == "男眾").CountAsync();
|
.Where(guest => guest.StatusCode != "404")
|
||||||
var guadanPeopleFemale = await _db.GuaDanOrderGuest.Where(a => a.IsDeleted == false && a.follower.sex == "女眾").CountAsync();
|
.CountAsync();
|
||||||
dynamic bedCounts = await RegionAndRoomAndBedSchedule.GetAvailableBedCountsAsync(_db, DateTime.Now, DateTime.Now);
|
var guadanPeopleMale = await _db.GuaDanOrderGuest
|
||||||
var guadanCurrentCount = await _db.GuaDanOrder.Where(a => now < a.EndDate).CountAsync();
|
.Where(guest => guest.StatusCode != "404")
|
||||||
var guadanPeopleCurrent = await _db.GuaDanOrderGuest.Where( a => a.CheckOutAt > now).CountAsync();
|
.Where(a => a.IsDeleted == false && a.followers.sex == "男眾")
|
||||||
var guadanPeopleCurrentMale = await _db.GuaDanOrderGuest.Where(a => a.CheckOutAt > now && a.follower.sex == "男眾").CountAsync();
|
.CountAsync();
|
||||||
var guadanPeopleCurrentFemale = await _db.GuaDanOrderGuest.Where(a => a.CheckOutAt > now && a.follower.sex == "女眾").CountAsync();
|
var guadanPeopleFemale = await _db.GuaDanOrderGuest
|
||||||
|
.Where(guest => guest.StatusCode != "404")
|
||||||
|
.Where(a => a.IsDeleted == false && a.followers.sex == "女眾")
|
||||||
|
.CountAsync();
|
||||||
|
var guadanPeopleCurrent = await _db.GuaDanOrderGuest
|
||||||
|
.Where(a => a.IsDeleted == false)
|
||||||
|
.Where(guest => guest.StatusCode != "404")
|
||||||
|
.Where(guest => guest.StatusCode != "403")
|
||||||
|
.Where( a => a.CheckOutAt >= now.Date)
|
||||||
|
.CountAsync();
|
||||||
|
var guadanPeopleCurrentMale = await _db.GuaDanOrderGuest
|
||||||
|
.Where(a => a.IsDeleted == false)
|
||||||
|
.Where(guest => guest.StatusCode != "404")
|
||||||
|
.Where(guest => guest.StatusCode != "403")
|
||||||
|
.Where(a => a.CheckOutAt >= now.Date && a.followers.sex == "男眾")
|
||||||
|
.CountAsync();
|
||||||
|
var guadanPeopleCurrentFemale = await _db.GuaDanOrderGuest
|
||||||
|
.Where(a => a.IsDeleted == false)
|
||||||
|
.Where(guest => guest.StatusCode != "404")
|
||||||
|
.Where(guest => guest.StatusCode != "403")
|
||||||
|
.Where(a => a.CheckOutAt >= now.Date && a.followers.sex == "女眾")
|
||||||
|
.CountAsync();
|
||||||
|
|
||||||
var result = new
|
var result = new
|
||||||
{
|
{
|
||||||
roomStatistics = new
|
|
||||||
{
|
|
||||||
roomCount = roomCount,
|
|
||||||
emptyRoomCount = emptyRoomCount,
|
|
||||||
bedCount = bedCount,
|
|
||||||
maleBedCount = maleBedCount,
|
|
||||||
femaleBedCount = femaleBedCount,
|
|
||||||
emptyBedCount = bedCounts.male + bedCounts.female,
|
|
||||||
emptyMaleBedCount = bedCounts.male,
|
|
||||||
emptyFemaleBedCount = bedCounts.female
|
|
||||||
},
|
|
||||||
guadanStatistics = new
|
guadanStatistics = new
|
||||||
{
|
{
|
||||||
guadanTotalCount = guadanTotalCount, // 总挂单次数
|
guadanTotalCount = guadanTotalCount, // 总挂单次数
|
||||||
@@ -61,7 +71,7 @@ public class guadanStatisticsController: ApiController
|
|||||||
guadanPeopleTotal = guadanPeopleTotal, // 总挂单人数
|
guadanPeopleTotal = guadanPeopleTotal, // 总挂单人数
|
||||||
guadanPeopleMale = guadanPeopleMale,
|
guadanPeopleMale = guadanPeopleMale,
|
||||||
guadanPeopleFemale = guadanPeopleFemale,
|
guadanPeopleFemale = guadanPeopleFemale,
|
||||||
guadanPeopleCurrent = guadanPeopleCurrent, // 当前挂单人数
|
guadanPeopleCurrent = guadanPeopleCurrent, // 已預約掛單人數
|
||||||
guadanPeopleCurrentMale = guadanPeopleCurrentMale,
|
guadanPeopleCurrentMale = guadanPeopleCurrentMale,
|
||||||
guadanPeopleCurrentFemale = guadanPeopleCurrentFemale
|
guadanPeopleCurrentFemale = guadanPeopleCurrentFemale
|
||||||
}
|
}
|
||||||
|
|||||||
93
web/App_Code/api/guadanStatisticsTableController.cs
Normal file
93
web/App_Code/api/guadanStatisticsTableController.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Http;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// guadanStatisticsTable 的摘要描述
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
[ezAuthorize]
|
||||||
|
public class guadanStatisticsTableController: ApiController
|
||||||
|
{
|
||||||
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
|
public guadanStatisticsTableController()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// TODO: 在這裡新增建構函式邏輯
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/guadan/guadanstatisticstable/list")]
|
||||||
|
public IHttpActionResult Get([FromUri] DateTime? start, [FromUri] DateTime? end)
|
||||||
|
{
|
||||||
|
// 如果兩個都為空,設定 start = 今天,end = 一個月後
|
||||||
|
if (!start.HasValue && !end.HasValue)
|
||||||
|
{
|
||||||
|
start = DateTime.Today;
|
||||||
|
end = DateTime.Today.AddMonths(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有 start 沒有 end,就給 end 預設一個月後
|
||||||
|
if (start.HasValue && !end.HasValue)
|
||||||
|
{
|
||||||
|
end = start.Value.Date.AddMonths(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有 end 沒有 start,就給 start 預設 end 的前一個月
|
||||||
|
if (!start.HasValue && end.HasValue)
|
||||||
|
{
|
||||||
|
start = end.Value.Date.AddMonths(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最後確保只取 date 部分
|
||||||
|
var startDate = start.Value.Date;
|
||||||
|
var endDate = end.Value.Date;
|
||||||
|
|
||||||
|
// 查詢資料庫時就用 date 型別對應
|
||||||
|
var statistics = _db.RegionAndRoomAndBedSchedule
|
||||||
|
.Where(s => s.IsCancel == false)
|
||||||
|
.Where(s => s.ScheduleDate >= startDate && s.ScheduleDate <= endDate)
|
||||||
|
.GroupBy(s => s.ScheduleDate)
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
date = g.Key,
|
||||||
|
todaytotalbookers = g.Count(), // 该日期的总记录数
|
||||||
|
checkin = g.Key <= DateTime.Today
|
||||||
|
? g.Count(x => x.GuaDanOrderGuest.RegionRoomBedStatus.Code == "402"
|
||||||
|
|| x.GuaDanOrderGuest.RegionRoomBedStatus.Code == "403")
|
||||||
|
: 0,
|
||||||
|
checkinfemale = g.Key <= DateTime.Today
|
||||||
|
? g.Count(x => (x.GuaDanOrderGuest.RegionRoomBedStatus.Code == "402"
|
||||||
|
|| x.GuaDanOrderGuest.RegionRoomBedStatus.Code == "403")
|
||||||
|
&& x.GuaDanOrderGuest.followers.sex == "女眾")
|
||||||
|
: 0,
|
||||||
|
checkinmale = g.Key <= DateTime.Today
|
||||||
|
? g.Count(x => (x.GuaDanOrderGuest.RegionRoomBedStatus.Code == "402"
|
||||||
|
|| x.GuaDanOrderGuest.RegionRoomBedStatus.Code == "403")
|
||||||
|
&& x.GuaDanOrderGuest.followers.sex == "男眾")
|
||||||
|
: 0,
|
||||||
|
bookfemale = g.Count(x => x.GuaDanOrderGuest.followers.sex == "女眾"),
|
||||||
|
bookmale = g.Count(x => x.GuaDanOrderGuest.followers.sex == "男眾")
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.date)
|
||||||
|
.ToList();
|
||||||
|
var todayDate = DateTime.Today;
|
||||||
|
|
||||||
|
var bedcount = _db.RegionRoomBed
|
||||||
|
.Where(a => a.IsDeleted == false)
|
||||||
|
.Count();
|
||||||
|
var roomcount = _db.Room.Count();
|
||||||
|
var result = new
|
||||||
|
{
|
||||||
|
bedcount,
|
||||||
|
roomcount,
|
||||||
|
statistics,
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ using System.Web.Http;
|
|||||||
/// lianyouController 的摘要描述
|
/// lianyouController 的摘要描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ezAuthorize]
|
[ezAuthorize]
|
||||||
public class lianyouController: ApiController
|
public class lianyouController : ApiController
|
||||||
{
|
{
|
||||||
private Model.ezEntities _db = new Model.ezEntities();
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
|
|
||||||
@@ -19,13 +19,34 @@ public class lianyouController: ApiController
|
|||||||
[Route("api/lianyou/getfollowers")]
|
[Route("api/lianyou/getfollowers")]
|
||||||
public async Task<IHttpActionResult> GetGuadanFollowers(int page, int pageSize, string searchName = null)
|
public async Task<IHttpActionResult> GetGuadanFollowers(int page, int pageSize, string searchName = null)
|
||||||
{
|
{
|
||||||
var qry = _db.followers.AsEnumerable();
|
// IQueryable 可讓 EF 在資料庫層面執行過濾和投影
|
||||||
if(searchName != null)
|
var qry = _db.followers.AsQueryable();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(searchName))
|
||||||
{
|
{
|
||||||
qry = qry.Where(a => (a.u_name ?? "").Contains(searchName) || (a.phone ?? "").Contains(searchName));
|
qry = qry.Where(a => (a.u_name ?? "").Contains(searchName) || (a.phone ?? "").Contains(searchName));
|
||||||
}
|
}
|
||||||
var count = qry.Count();
|
|
||||||
var data = qry.OrderBy(a => a.f_number).ToPagedList(page, pageSize);
|
var count = await qry.CountAsync();
|
||||||
return Ok(new {data = data, count = count});
|
|
||||||
|
// 投影到只需要的欄位
|
||||||
|
var projected = qry
|
||||||
|
.OrderBy(a => a.f_number)
|
||||||
|
.Select(a => new
|
||||||
|
{
|
||||||
|
num = a.num,
|
||||||
|
u_name = a.u_name,
|
||||||
|
phone = a.phone,
|
||||||
|
sex = a.sex,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 分頁
|
||||||
|
var data = projected
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.ToList(); // 如果使用 EF Core 可用 ToListAsync()
|
||||||
|
|
||||||
|
return Ok(new { data = data, count = count });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -22,94 +22,14 @@ public class orderdetailController:ApiController
|
|||||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.pro_order q, int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
public IHttpActionResult GetList([FromBody] Model.ViewModel.pro_order q, int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||||
{
|
{
|
||||||
int activity_num = Convert.ToInt32(q.activity_num);
|
int activity_num = Convert.ToInt32(q.activity_num);
|
||||||
|
//現在的牌位預覽只會出現功德主,修改為所有人都會出現
|
||||||
//var aIDt = _db.actItems.AsEnumerable().Where(f => f.subject.Contains(q.actItemTxt.Trim())).Select(f => f.num);//品項
|
//var aIDt = _db.actItems.AsEnumerable().Where(f => f.subject.Contains(q.actItemTxt.Trim())).Select(f => f.num);//品項
|
||||||
var OrderList = _db.pro_order.Where(u => u.activity_num == activity_num).Select(j => j.order_no).ToList();
|
//var OrderList = _db.pro_order.Where(u => u.activity_num == activity_num).Select(j => j.order_no).ToList();
|
||||||
var gdzOrderList = _db.pro_order_detail.Where(o => OrderList.Contains(o.order_no) && o.print_id.Contains("主")).Select(o => o.order_no).Distinct().ToList();
|
//var gdzOrderList = _db.pro_order_detail.Where(o => OrderList.Contains(o.order_no) && o.print_id.Contains("主")).Select(o => o.order_no).Distinct().ToList();
|
||||||
var qry = _db.pro_order.Where(u => gdzOrderList.Contains(u.order_no)).AsEnumerable();
|
//var qry = _db.pro_order.Where(u => gdzOrderList.Contains(u.order_no)).AsEnumerable();
|
||||||
if (!string.IsNullOrEmpty(q.order_no))
|
var qry = _db.pro_order.Where( u => u.activity_num == activity_num).AsEnumerable();
|
||||||
qry = qry.Where(o => o.order_no.Contains(q.order_no.Trim()));
|
|
||||||
if (!string.IsNullOrEmpty(q.keyin1))
|
qry = qry.OrderByDescending(o => o.reg_time);
|
||||||
qry = qry.Where(o => o.keyin1.Contains(q.keyin1));
|
|
||||||
if (q.f_num.HasValue && q.f_num > 0)
|
|
||||||
qry = qry.Where(o => o.f_num == q.f_num);
|
|
||||||
if (q.activity_num.HasValue && q.activity_num > 0)
|
|
||||||
qry = qry.Where(o => o.activity_num == q.activity_num);
|
|
||||||
if (q.up_time1.HasValue)
|
|
||||||
qry = qry.Where(o => o.up_time >= q.up_time1.Value);
|
|
||||||
if (q.up_time2.HasValue)
|
|
||||||
qry = qry.Where(o => o.up_time < Convert.ToDateTime(q.up_time2.Value).AddDays(1));
|
|
||||||
if (!string.IsNullOrEmpty(q.address))
|
|
||||||
qry = qry.Where(o => o.address.Contains(q.address.Trim()));
|
|
||||||
if (!string.IsNullOrEmpty(q.subject))
|
|
||||||
qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(q.subject?.Trim()));
|
|
||||||
if (!string.IsNullOrEmpty(q.u_name))
|
|
||||||
qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(q.u_name?.Trim()));
|
|
||||||
if (!string.IsNullOrEmpty(q.introducerTxt))
|
|
||||||
qry = qry.Where(o => o.introducer.HasValue && o.follower1.u_name.Contains(q.introducerTxt?.Trim()));
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(q.actItemTxt))
|
|
||||||
{
|
|
||||||
//qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.order_no == o.order_no && aIDt.ToArray().Contains(f2.actItem_num?.ToString())).Count() > 0);
|
|
||||||
// qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.order_no == o.order_no && aIDt.Any(x => x == f2.actItem_num)).Count() > 0);
|
|
||||||
|
|
||||||
qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem.subject.Contains(q.actItemTxt?.Trim())).Count() > 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(q.country))
|
|
||||||
qry = qry.Where(o => o.f_num != null && o.follower?.country == q.country);
|
|
||||||
if (!string.IsNullOrEmpty(q.country2))
|
|
||||||
{
|
|
||||||
if (q.country2 == "1")
|
|
||||||
{
|
|
||||||
qry = qry.Where(o => o.f_num != null && o.follower?.country == "158");
|
|
||||||
}
|
|
||||||
else if (q.country2 == "2")
|
|
||||||
{
|
|
||||||
qry = qry.Where(o => o.f_num != null && o.follower?.country != "158");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (sortBy.Equals("order_no"))
|
|
||||||
{
|
|
||||||
if (sortDesc)
|
|
||||||
qry = qry.OrderByDescending(o => o.order_no);
|
|
||||||
else
|
|
||||||
qry = qry.OrderBy(o => o.order_no);
|
|
||||||
}
|
|
||||||
else if (sortBy.Equals("keyin1_txt"))
|
|
||||||
{
|
|
||||||
if (sortDesc)
|
|
||||||
qry = qry.OrderByDescending(o => o.keyin1);
|
|
||||||
else
|
|
||||||
qry = qry.OrderBy(o => o.keyin1);
|
|
||||||
}
|
|
||||||
else if (sortBy.Equals("up_time"))
|
|
||||||
{
|
|
||||||
if (sortDesc)
|
|
||||||
qry = qry.OrderByDescending(o => o.up_time);
|
|
||||||
else
|
|
||||||
qry = qry.OrderBy(o => o.up_time);
|
|
||||||
}
|
|
||||||
else if (sortBy.Equals("u_name"))
|
|
||||||
{
|
|
||||||
if (sortDesc)
|
|
||||||
qry = qry.OrderByDescending(o => o.follower?.u_name);
|
|
||||||
else
|
|
||||||
qry = qry.OrderBy(o => o.follower?.u_name);
|
|
||||||
}
|
|
||||||
else if (sortBy.Equals("subject"))
|
|
||||||
{
|
|
||||||
if (sortDesc)
|
|
||||||
qry = qry.OrderByDescending(o => o.activity?.subject);
|
|
||||||
else
|
|
||||||
qry = qry.OrderBy(o => o.activity?.subject);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
qry = qry.OrderByDescending(o => o.reg_time);
|
|
||||||
|
|
||||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||||
var ret = new
|
var ret = new
|
||||||
@@ -125,7 +45,11 @@ public class orderdetailController:ApiController
|
|||||||
up_time = x.up_time,
|
up_time = x.up_time,
|
||||||
keyin1_txt = Model.pro_order.keyin1_value_to_text(x.keyin1),
|
keyin1_txt = Model.pro_order.keyin1_value_to_text(x.keyin1),
|
||||||
//detail = x.pro_order_detail.Where(u => u.printed_files != null)
|
//detail = x.pro_order_detail.Where(u => u.printed_files != null)
|
||||||
detail = new { count = x.pro_order_detail.Where(u => u.actItem.act_bom.Count() == 0).Count(),
|
detail = new { count = x.pro_order_detail
|
||||||
|
.Where(u => (u.parent_num != null)
|
||||||
|
|| u.actItem.subject.Contains("牌")
|
||||||
|
|| !string.IsNullOrEmpty(u.f_num_tablet))
|
||||||
|
.Count(),
|
||||||
actItem = x.pro_order_detail.Where(u => u.printed_files != null).FirstOrDefault()?.print_id }
|
actItem = x.pro_order_detail.Where(u => u.printed_files != null).FirstOrDefault()?.print_id }
|
||||||
}),
|
}),
|
||||||
count = count
|
count = count
|
||||||
|
|||||||
250
web/App_Code/api/pivot01Controller.cs
Normal file
250
web/App_Code/api/pivot01Controller.cs
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web.Http;
|
||||||
|
using System.Configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// pivot01Controller - 法會報名統計分析 API
|
||||||
|
/// 設計理念:直接查詢 SQL VIEW,保持彈性與簡潔
|
||||||
|
/// </summary>
|
||||||
|
[ezAuthorize]
|
||||||
|
public class pivot01Controller : ApiController
|
||||||
|
{
|
||||||
|
// 連線字串
|
||||||
|
private readonly string _connectionString;
|
||||||
|
|
||||||
|
public pivot01Controller()
|
||||||
|
{
|
||||||
|
// 優先使用 shopConn 連線字串(純 SQL Server 連線字串)
|
||||||
|
var shopConnectionString = ConfigurationManager.ConnectionStrings["shopConn"]?.ConnectionString;
|
||||||
|
if (!string.IsNullOrEmpty(shopConnectionString))
|
||||||
|
{
|
||||||
|
// 移除不相容的 Provider 參數(包含 SQLOLEDB 和 SQLNCLI11)
|
||||||
|
_connectionString = shopConnectionString
|
||||||
|
.Replace("Provider=SQLOLEDB;", "")
|
||||||
|
.Replace("Provider=SQLNCLI11;", "")
|
||||||
|
.Replace(" Provider=SQLOLEDB", "")
|
||||||
|
.Replace(" Provider=SQLNCLI11", "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 備用方案:從 Entity Framework 連線字串中提取 SQL Server 連線字串
|
||||||
|
var efConnectionString = ConfigurationManager.ConnectionStrings["ezEntities"]?.ConnectionString;
|
||||||
|
if (!string.IsNullOrEmpty(efConnectionString))
|
||||||
|
{
|
||||||
|
// 解析 EF 連線字串,提取 provider connection string 部分
|
||||||
|
var startIndex = efConnectionString.IndexOf("provider connection string="") + "provider connection string="".Length;
|
||||||
|
var endIndex = efConnectionString.LastIndexOf(""");
|
||||||
|
if (startIndex > 0 && endIndex > startIndex)
|
||||||
|
{
|
||||||
|
_connectionString = efConnectionString.Substring(startIndex, endIndex - startIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("無法解析 Entity Framework 連線字串");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("找不到可用的資料庫連線字串");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 通用 VIEW 查詢方法
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 執行 SQL 查詢並回傳 DataTable
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">SQL 查詢語句</param>
|
||||||
|
/// <param name="parameters">參數陣列</param>
|
||||||
|
/// <returns>查詢結果 DataTable</returns>
|
||||||
|
private DataTable ExecuteSqlQuery(string sql, SqlParameter[] parameters = null)
|
||||||
|
{
|
||||||
|
var dataTable = new DataTable();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(_connectionString))
|
||||||
|
using (var command = new SqlCommand(sql, connection))
|
||||||
|
{
|
||||||
|
// 設定逾時時間為 60 秒
|
||||||
|
command.CommandTimeout = 60;
|
||||||
|
|
||||||
|
// 加入參數
|
||||||
|
if (parameters != null && parameters.Length > 0)
|
||||||
|
{
|
||||||
|
command.Parameters.AddRange(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 開啟連線並執行查詢
|
||||||
|
connection.Open();
|
||||||
|
using (var adapter = new SqlDataAdapter(command))
|
||||||
|
{
|
||||||
|
adapter.Fill(dataTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SqlException ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"SQL 查詢錯誤: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"執行查詢時發生錯誤: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DataTable 轉換為動態物件列表(保留中文欄位名)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt">DataTable</param>
|
||||||
|
/// <returns>Dictionary 列表</returns>
|
||||||
|
private List<Dictionary<string, object>> DataTableToDictionary(DataTable dt)
|
||||||
|
{
|
||||||
|
var list = new List<Dictionary<string, object>>();
|
||||||
|
|
||||||
|
foreach (DataRow row in dt.Rows)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, object>();
|
||||||
|
foreach (DataColumn col in dt.Columns)
|
||||||
|
{
|
||||||
|
// 保留原始欄位名稱(包含中文)
|
||||||
|
dict[col.ColumnName] = row[col] == DBNull.Value ? null : row[col];
|
||||||
|
}
|
||||||
|
list.Add(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region API 端點
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GET /api/pivot01/activity_stats
|
||||||
|
/// 查詢法會統計(對應「法會統計」VIEW)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="year">查詢年份</param>
|
||||||
|
/// <returns>法會統計資料</returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/pivot01/activity_stats")]
|
||||||
|
public IHttpActionResult GetActivityStats(int year)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 驗證年份參數
|
||||||
|
if (year < 1900 || year > 2100)
|
||||||
|
{
|
||||||
|
return BadRequest("年份參數不正確,請輸入 1900 ~ 2100 之間的年份");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建立 SQL 查詢(包含當年度及無日期的法會)
|
||||||
|
string sql = @"
|
||||||
|
SELECT * FROM [法會統計]
|
||||||
|
WHERE (YEAR(開始日期) = @year OR 開始日期 IS NULL)
|
||||||
|
ORDER BY
|
||||||
|
CASE WHEN 開始日期 IS NULL THEN 1 ELSE 0 END,
|
||||||
|
開始日期 DESC,
|
||||||
|
結束日期 DESC
|
||||||
|
";
|
||||||
|
|
||||||
|
// 建立參數
|
||||||
|
var parameters = new[]
|
||||||
|
{
|
||||||
|
new SqlParameter("@year", SqlDbType.Int) { Value = year }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 執行查詢
|
||||||
|
var dataTable = ExecuteSqlQuery(sql, parameters);
|
||||||
|
var data = DataTableToDictionary(dataTable);
|
||||||
|
|
||||||
|
// 回應結果
|
||||||
|
var result = new
|
||||||
|
{
|
||||||
|
success = true,
|
||||||
|
data = data,
|
||||||
|
message = "查詢成功",
|
||||||
|
rowCount = data.Count
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var errorResponse = new
|
||||||
|
{
|
||||||
|
success = false,
|
||||||
|
message = $"查詢失敗:{ex.Message}",
|
||||||
|
error = ex.ToString()
|
||||||
|
};
|
||||||
|
return Content(System.Net.HttpStatusCode.BadRequest, errorResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GET /api/pivot01/registration_details
|
||||||
|
/// 查詢報名明細(對應「報名明細查詢」VIEW)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="activityNum">法會編號(必填)</param>
|
||||||
|
/// <returns>報名明細資料</returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Route("api/pivot01/registration_details")]
|
||||||
|
public IHttpActionResult GetRegistrationDetails(int? activityNum = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 驗證參數
|
||||||
|
if (!activityNum.HasValue || activityNum.Value <= 0)
|
||||||
|
{
|
||||||
|
return BadRequest("請提供有效的法會編號(activityNum)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建立查詢 SQL
|
||||||
|
string sql = @"
|
||||||
|
SELECT * FROM [報名明細查詢]
|
||||||
|
WHERE 法會ID = @activityNum
|
||||||
|
ORDER BY 報名日期 DESC, 報名編號 DESC
|
||||||
|
";
|
||||||
|
|
||||||
|
// 建立參數
|
||||||
|
var parameters = new[]
|
||||||
|
{
|
||||||
|
new SqlParameter("@activityNum", SqlDbType.Int) { Value = activityNum.Value }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 執行查詢
|
||||||
|
var dataTable = ExecuteSqlQuery(sql, parameters);
|
||||||
|
var data = DataTableToDictionary(dataTable);
|
||||||
|
|
||||||
|
// 回應結果
|
||||||
|
var result = new
|
||||||
|
{
|
||||||
|
success = true,
|
||||||
|
data = data,
|
||||||
|
message = "查詢成功",
|
||||||
|
rowCount = data.Count
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var errorResponse = new
|
||||||
|
{
|
||||||
|
success = false,
|
||||||
|
message = $"查詢失敗:{ex.Message}",
|
||||||
|
error = ex.ToString()
|
||||||
|
};
|
||||||
|
return Content(System.Net.HttpStatusCode.BadRequest, errorResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
1142
web/App_Code/api/pivotController.cs
Normal file
1142
web/App_Code/api/pivotController.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing.Drawing2D;
|
using System.Drawing.Drawing2D;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using System.Web.Http;
|
using System.Web.Http;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
@@ -11,7 +12,7 @@ using System.Web.Routing;
|
|||||||
/// regionController 的摘要描述
|
/// regionController 的摘要描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ezAuthorize]
|
[ezAuthorize]
|
||||||
public class regionController: ApiController
|
public class regionController : ApiController
|
||||||
{
|
{
|
||||||
private Model.ezEntities _db = new Model.ezEntities();
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
public regionController()
|
public regionController()
|
||||||
@@ -39,8 +40,9 @@ public class regionController: ApiController
|
|||||||
var startDate = filter.StartDate.Date;
|
var startDate = filter.StartDate.Date;
|
||||||
var endDate = filter.EndDate.Date;
|
var endDate = filter.EndDate.Date;
|
||||||
|
|
||||||
var query = _db.Region
|
var query = _db.Region//區域狀態是否啟用這裡只設置了過濾了有客房的區域,是否要過濾所有
|
||||||
.Where(r => !r.IsDeleted)
|
.Where(r => !r.IsDeleted)
|
||||||
|
.Where(r => r.IsActive)
|
||||||
.Where(r => r.Room.Any());
|
.Where(r => r.Room.Any());
|
||||||
|
|
||||||
if (filter.Gender != null)
|
if (filter.Gender != null)
|
||||||
@@ -67,6 +69,7 @@ public class regionController: ApiController
|
|||||||
r.Uuid,
|
r.Uuid,
|
||||||
r.Name,
|
r.Name,
|
||||||
regionPath = r.Name,
|
regionPath = r.Name,
|
||||||
|
isStop = !IsRegionAvailable(r.Uuid),
|
||||||
Room = r.Room
|
Room = r.Room
|
||||||
.Where(room => filter.Gender == null || room.Gender == filter.Gender)
|
.Where(room => filter.Gender == null || room.Gender == filter.Gender)
|
||||||
.Where(room =>
|
.Where(room =>
|
||||||
@@ -95,17 +98,19 @@ public class regionController: ApiController
|
|||||||
bed.Name,
|
bed.Name,
|
||||||
bed.Gender,
|
bed.Gender,
|
||||||
bed.RoomUuid,
|
bed.RoomUuid,
|
||||||
bed.StatusUuid,
|
bed.StatusCode,
|
||||||
bed.IsActive,
|
bed.IsActive,
|
||||||
bed.IsDeleted,
|
bed.IsDeleted,
|
||||||
canuse = bed.IsAvailableDuring(startDate, endDate, _db),
|
canuse = bed.IsAvailableDuring(startDate, endDate, _db),
|
||||||
statusname = bed.RegionRoomBedStatus.Name,
|
statusname = bed.RegionRoomBedStatus.Name,
|
||||||
schedules = _db.RegionAndRoomAndBedSchedule
|
schedules = _db.RegionAndRoomAndBedSchedule
|
||||||
|
.Where(s => s.IsCancel == false)
|
||||||
.Where(s => s.TargetUuid == bed.Uuid
|
.Where(s => s.TargetUuid == bed.Uuid
|
||||||
&& s.IsDeleted == false
|
&& s.IsDeleted == false
|
||||||
&& s.IsActive
|
|
||||||
&& (s.ScheduleDate == null
|
&& (s.ScheduleDate == null
|
||||||
|| (s.ScheduleDate >= startDate && s.ScheduleDate <= endDate)))
|
|| (s.ScheduleDate >= startDate)))
|
||||||
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "403" && s.GuaDanOrderGuest.StatusCode != "404")
|
||||||
|
.OrderBy(a => a.ScheduleDate)
|
||||||
.Select(s => new
|
.Select(s => new
|
||||||
{
|
{
|
||||||
s.Uuid,
|
s.Uuid,
|
||||||
@@ -113,7 +118,15 @@ public class regionController: ApiController
|
|||||||
s.UseType,
|
s.UseType,
|
||||||
s.Title,
|
s.Title,
|
||||||
s.Description,
|
s.Description,
|
||||||
s.GuaDanOrderNo
|
s.GuaDanOrderNo,
|
||||||
|
s.TargetUuid,
|
||||||
|
usename = _db.GuaDanOrderGuest
|
||||||
|
.Where(guest => guest.GuaDanOrderNo == s.GuaDanOrderNo)
|
||||||
|
.Where(guest => guest.BedUuid == s.TargetUuid)
|
||||||
|
.Select(guest => guest.followers.u_name)
|
||||||
|
.FirstOrDefault()
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
.ToList()
|
.ToList()
|
||||||
}),
|
}),
|
||||||
@@ -138,6 +151,30 @@ public class regionController: ApiController
|
|||||||
Summary = summary,
|
Summary = summary,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public bool IsRegionAvailable(Guid regionUuid)
|
||||||
|
{
|
||||||
|
var current = _db.Region.FirstOrDefault(r => r.Uuid == regionUuid);
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
// 當前區域不可用就直接返回 false
|
||||||
|
if (!current.IsActive || current.IsDeleted)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 沒有父區域了,說明一路上都可用
|
||||||
|
if (!current.ParentUuid.HasValue)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 繼續往父區域走
|
||||||
|
current = _db.Region.FirstOrDefault(r => r.Uuid == current.ParentUuid.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 沒查到(極端情況,比如資料庫被改了)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 遞迴生成區域完整路徑
|
/// 遞迴生成區域完整路徑
|
||||||
@@ -183,7 +220,8 @@ public class regionController: ApiController
|
|||||||
IsActive = region.IsActive,
|
IsActive = region.IsActive,
|
||||||
RoomCount = region.RoomCount,
|
RoomCount = region.RoomCount,
|
||||||
BedDto = new List<BedDto>(),
|
BedDto = new List<BedDto>(),
|
||||||
Rooms = region.Room.Select(a => new RoomDto {
|
Rooms = region.Room.Select(a => new RoomDto
|
||||||
|
{
|
||||||
Uuid = a.Uuid,
|
Uuid = a.Uuid,
|
||||||
Name = a.Name,
|
Name = a.Name,
|
||||||
RegionUuid = a.RegionUuid,
|
RegionUuid = a.RegionUuid,
|
||||||
@@ -194,13 +232,13 @@ public class regionController: ApiController
|
|||||||
{
|
{
|
||||||
Uuid = c.Uuid,
|
Uuid = c.Uuid,
|
||||||
name = c.Name,
|
name = c.Name,
|
||||||
roomUuid = c.RoomUuid,
|
roomUuid = c.RoomUuid,
|
||||||
isactive = c.IsActive,
|
isactive = c.IsActive,
|
||||||
statusuuid = c.StatusUuid,
|
statuscode = c.StatusCode,
|
||||||
Gender = c.Gender,
|
Gender = c.Gender,
|
||||||
|
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
|
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
Children = allRegions
|
Children = allRegions
|
||||||
.Where(r => r.ParentUuid == region.Uuid)
|
.Where(r => r.ParentUuid == region.Uuid)
|
||||||
@@ -216,25 +254,25 @@ public class regionController: ApiController
|
|||||||
{
|
{
|
||||||
var allRegions = _db.Region.ToList();
|
var allRegions = _db.Region.ToList();
|
||||||
|
|
||||||
// 根区域
|
// 根區域
|
||||||
var rootRegions = allRegions
|
var rootRegions = allRegions
|
||||||
.Where(r => r.ParentUuid == null)
|
.Where(r => r.ParentUuid == null)
|
||||||
.OrderBy(r => r.SortOrder)
|
.OrderBy(r => r.SortOrder)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// 生成树并按性别过滤
|
// 生成樹並按性別過濾
|
||||||
var tree = rootRegions
|
var tree = rootRegions
|
||||||
.Select(r => BuildRegionDtoByGender(r, allRegions, request.IsMale))
|
.Select(r => BuildRegionDtoByGender(r, allRegions, request.IsMale))
|
||||||
.Where(r => r != null) // 去掉没有房间的区域
|
.Where(r => r != null) // 去掉沒有房間的區域
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return Ok(tree);
|
return Ok(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据性别过滤房间的 BuildRegionDto
|
// 根據性別過濾房間的 BuildRegionDto
|
||||||
private RegionDto BuildRegionDtoByGender(Region region, List<Region> allRegions, bool? gender)
|
private RegionDto BuildRegionDtoByGender(Region region, List<Region> allRegions, bool? gender)
|
||||||
{
|
{
|
||||||
// 过滤房间按性别
|
// 過濾房間按性別
|
||||||
var rooms = region.Room?
|
var rooms = region.Room?
|
||||||
.Where(a => !gender.HasValue || a.Gender == gender.Value)
|
.Where(a => !gender.HasValue || a.Gender == gender.Value)
|
||||||
.Select(a => new RoomDto
|
.Select(a => new RoomDto
|
||||||
@@ -251,19 +289,19 @@ public class regionController: ApiController
|
|||||||
name = c.Name,
|
name = c.Name,
|
||||||
roomUuid = c.RoomUuid,
|
roomUuid = c.RoomUuid,
|
||||||
isactive = c.IsActive,
|
isactive = c.IsActive,
|
||||||
statusuuid = c.StatusUuid
|
statuscode = c.StatusCode,
|
||||||
}).ToList()
|
}).ToList()
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// 递归生成子区域
|
// 遞迴生成子區域
|
||||||
var children = allRegions
|
var children = allRegions
|
||||||
.Where(r => r.ParentUuid == region.Uuid)
|
.Where(r => r.ParentUuid == region.Uuid)
|
||||||
.Select(child => BuildRegionDtoByGender(child, allRegions, gender))
|
.Select(child => BuildRegionDtoByGender(child, allRegions, gender))
|
||||||
.Where(c => c != null) // 去掉没有房间的子区域
|
.Where(c => c != null) // 去掉沒有房間的子區域
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// 如果这个区域既没有房间也没有子区域,则返回 null
|
// 如果這個區域既沒有房間也沒有子區域,則返回 null
|
||||||
if (!rooms.Any() && !children.Any())
|
if (!rooms.Any() && !children.Any())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -281,14 +319,14 @@ public class regionController: ApiController
|
|||||||
BedDto = new List<BedDto>(),
|
BedDto = new List<BedDto>(),
|
||||||
Children = children,
|
Children = children,
|
||||||
Gender = region.Gender,
|
Gender = region.Gender,
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求模型
|
// 請求模型
|
||||||
public class GenderRequest
|
public class GenderRequest
|
||||||
{
|
{
|
||||||
public bool? IsMale { get; set; } // true = 男, false = 女, null = 不过滤
|
public bool? IsMale { get; set; } // true = 男, false = 女, null = 不過濾
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RoomDto
|
public class RoomDto
|
||||||
@@ -303,11 +341,12 @@ public class regionController: ApiController
|
|||||||
public Nullable<System.DateTime> UpdatedAt { get; set; }
|
public Nullable<System.DateTime> UpdatedAt { get; set; }
|
||||||
public List<BedDto> beds { get; set; }
|
public List<BedDto> beds { get; set; }
|
||||||
}
|
}
|
||||||
public class BedDto {
|
public class BedDto
|
||||||
|
{
|
||||||
public Guid Uuid { get; set; }
|
public Guid Uuid { get; set; }
|
||||||
public Guid? roomUuid { get; set; }
|
public Guid? roomUuid { get; set; }
|
||||||
public string name { get; set; }
|
public string name { get; set; }
|
||||||
public Guid? statusuuid { get; set; }
|
public string statuscode { get; set; }
|
||||||
public bool isactive { get; set; }
|
public bool isactive { get; set; }
|
||||||
public bool Gender { get; set; }
|
public bool Gender { get; set; }
|
||||||
}
|
}
|
||||||
@@ -324,13 +363,13 @@ public class regionController: ApiController
|
|||||||
public bool IsActive { get; set; } = true;
|
public bool IsActive { get; set; } = true;
|
||||||
public int? RoomCount { get; set; }
|
public int? RoomCount { get; set; }
|
||||||
public List<RoomDto> Rooms { get; set; }
|
public List<RoomDto> Rooms { get; set; }
|
||||||
public List<BedDto> BedDto { get; set; }
|
public List<BedDto> BedDto { get; set; }
|
||||||
public bool? Gender { get; set; }
|
public bool? Gender { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/region/create")]
|
[Route("api/region/create")]
|
||||||
public IHttpActionResult createRegion([FromBody] RegionDto dto)
|
public IHttpActionResult createRegion([FromBody] RegionDto dto)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(dto.Name))
|
if (string.IsNullOrWhiteSpace(dto.Name))
|
||||||
return BadRequest("區域名稱為必填");
|
return BadRequest("區域名稱為必填");
|
||||||
@@ -361,6 +400,28 @@ public class regionController: ApiController
|
|||||||
var region = _db.Region.FirstOrDefault(r => r.Uuid == dto.Uuid);
|
var region = _db.Region.FirstOrDefault(r => r.Uuid == dto.Uuid);
|
||||||
if (region == null)
|
if (region == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
if (dto.RoomCount < region.Room.Count())
|
||||||
|
{
|
||||||
|
return BadRequest("客房數量小於已存在的客房數量");
|
||||||
|
}
|
||||||
|
if (dto.IsActive == false)
|
||||||
|
{
|
||||||
|
var regionIds = GetAllRegionIds(region.Uuid);
|
||||||
|
var hasPendingBeds = _db.RegionRoomBed
|
||||||
|
.Where(b => regionIds.Contains(b.Room.RegionUuid))
|
||||||
|
.SelectMany(b => b.GuaDanOrderGuest)
|
||||||
|
.Any(g => !g.IsDeleted &&
|
||||||
|
(g.RegionRoomBedStatus.Code == GuaDanOrderGuest.STATUS_BOOKED || // 預約中
|
||||||
|
g.RegionRoomBedStatus.Code == GuaDanOrderGuest.STATUS_CHECKED_IN)); // 已入住
|
||||||
|
if (hasPendingBeds)
|
||||||
|
{
|
||||||
|
return Content(HttpStatusCode.BadRequest, new
|
||||||
|
{
|
||||||
|
code = "BED_IS_USED",
|
||||||
|
message = "該區域有床位正在掛單中,請先處理"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
region.Name = dto.Name;
|
region.Name = dto.Name;
|
||||||
region.Description = dto.Description;
|
region.Description = dto.Description;
|
||||||
region.SortOrder = dto.SortOrder;
|
region.SortOrder = dto.SortOrder;
|
||||||
@@ -399,6 +460,25 @@ public class regionController: ApiController
|
|||||||
return Ok(new { message = "刪除成功" });
|
return Ok(new { message = "刪除成功" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Guid> GetAllRegionIds(Guid regionUuid)
|
||||||
|
{
|
||||||
|
var regionIds = new List<Guid> { regionUuid };
|
||||||
|
|
||||||
|
var children = _db.Region
|
||||||
|
.Where(r => r.ParentUuid == regionUuid)
|
||||||
|
.Select(r => r.Uuid)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var childId in children)
|
||||||
|
{
|
||||||
|
regionIds.AddRange(GetAllRegionIds(childId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return regionIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 遞迴刪除子節點
|
// 遞迴刪除子節點
|
||||||
private void DeleteRegionRecursive(Region region)
|
private void DeleteRegionRecursive(Region region)
|
||||||
{
|
{
|
||||||
@@ -412,7 +492,7 @@ public class regionController: ApiController
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/region/getRegionType")]
|
[Route("api/region/getRegionType")]
|
||||||
public IHttpActionResult getRegionType()
|
public IHttpActionResult getRegionType()
|
||||||
{
|
{
|
||||||
var data = _db.RegionType.Where(a => a.IsActive == true).ToList();
|
var data = _db.RegionType.Where(a => a.IsActive == true).ToList();
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
}
|
}
|
||||||
@@ -421,7 +501,7 @@ public class regionController: ApiController
|
|||||||
[Route("api/region/regionwithroom")]
|
[Route("api/region/regionwithroom")]
|
||||||
public IHttpActionResult GetRegionWithRoom()
|
public IHttpActionResult GetRegionWithRoom()
|
||||||
{
|
{
|
||||||
//返回有房间的region
|
//返回有房間的region
|
||||||
var data = _db.Region.Where(a => a.Room.Count() > 0)
|
var data = _db.Region.Where(a => a.Room.Count() > 0)
|
||||||
.Select(r => new
|
.Select(r => new
|
||||||
{
|
{
|
||||||
@@ -431,7 +511,9 @@ public class regionController: ApiController
|
|||||||
r.Gender,
|
r.Gender,
|
||||||
rooms = r.Room.Select(room => new
|
rooms = r.Room.Select(room => new
|
||||||
{
|
{
|
||||||
room.Uuid, room.Name, room.RegionUuid
|
room.Uuid,
|
||||||
|
room.Name,
|
||||||
|
room.RegionUuid
|
||||||
}).ToList()
|
}).ToList()
|
||||||
}).ToList();
|
}).ToList();
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
@@ -440,7 +522,7 @@ public class regionController: ApiController
|
|||||||
[Route("api/room/roomwithbed")]
|
[Route("api/room/roomwithbed")]
|
||||||
public IHttpActionResult GetRoomWithBed(Guid? RegionUuid = null)
|
public IHttpActionResult GetRoomWithBed(Guid? RegionUuid = null)
|
||||||
{
|
{
|
||||||
//获取所有有床位的房间
|
//獲取所有有床位的房間
|
||||||
var query = _db.Room
|
var query = _db.Room
|
||||||
.Select(r => new
|
.Select(r => new
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.Entity;
|
using System.Data.Entity;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using System.Web.Http;
|
using System.Web.Http;
|
||||||
@@ -40,24 +41,23 @@ public class regionRoomBedController : ApiController
|
|||||||
.Where(a => a.RoomUuid == roomUuid)
|
.Where(a => a.RoomUuid == roomUuid)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// 取出所有相关排程
|
StartTime = StartTime.Date;
|
||||||
var schedules = _db.RegionAndRoomAndBedSchedule
|
EndTime = EndTime?.Date;
|
||||||
.Where(b => b.IsDeleted == false && b.IsActive)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var data = beds.Select(a =>
|
var data = beds.Select(a =>
|
||||||
{
|
{
|
||||||
// 在内存中处理日期比较
|
var bedSchedules = _db.RegionAndRoomAndBedSchedule
|
||||||
var bedSchedules = schedules
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "403")
|
||||||
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "404")
|
||||||
.Where(b => b.TargetUuid == a.Uuid
|
.Where(b => b.TargetUuid == a.Uuid
|
||||||
&& (b.ScheduleDate == null // 长期占用
|
&& (b.ScheduleDate == null
|
||||||
|| (b.ScheduleDate >= StartTime.Date && b.ScheduleDate <= EndTime.Value.Date)))
|
|| (b.ScheduleDate >= StartTime && b.ScheduleDate < EndTime)))
|
||||||
|
.ToList()
|
||||||
.Select(c => new
|
.Select(c => new
|
||||||
{
|
{
|
||||||
c.Uuid,
|
c.Uuid,
|
||||||
c.Description,
|
c.Description,
|
||||||
c.IsDeleted,
|
c.IsDeleted,
|
||||||
c.IsActive,
|
|
||||||
c.GuaDanOrderNo,
|
c.GuaDanOrderNo,
|
||||||
c.UseType,
|
c.UseType,
|
||||||
c.Title,
|
c.Title,
|
||||||
@@ -67,22 +67,51 @@ public class regionRoomBedController : ApiController
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
bool canUsed = !bedSchedules.Any();
|
bool canUsed = !bedSchedules.Any();
|
||||||
|
bool bedIsStop = IsBedStopped(a);
|
||||||
return new
|
return new
|
||||||
{
|
{
|
||||||
a.Uuid,
|
a.Uuid,
|
||||||
a.Name,
|
a.Name,
|
||||||
a.Gender,
|
a.Gender,
|
||||||
a.IsActive,
|
a.IsActive,
|
||||||
a.StatusUuid,
|
a.StatusCode,
|
||||||
a.RoomUuid,
|
a.RoomUuid,
|
||||||
canUsed,
|
canUsed,
|
||||||
|
bedIsStop,
|
||||||
schedule = bedSchedules
|
schedule = bedSchedules
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
}
|
}
|
||||||
|
public bool IsBedStopped(RegionRoomBed bed)
|
||||||
|
{
|
||||||
|
// 1️⃣ 床位本身不可用
|
||||||
|
if (!bed.IsActive || bed.IsDeleted)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 2️⃣ 所属房间不可用
|
||||||
|
var room = bed.Room;
|
||||||
|
if (room == null || !room.IsActive.Value || room.IsDeleted)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 3️⃣ 所属区域不可用
|
||||||
|
var region = room.Region;
|
||||||
|
while (region != null)
|
||||||
|
{
|
||||||
|
if (!region.IsActive || region.IsDeleted)
|
||||||
|
return true; // 有任意一级区域不可用就返回 true
|
||||||
|
|
||||||
|
if (!region.ParentUuid.HasValue)
|
||||||
|
break; // 到顶层了
|
||||||
|
|
||||||
|
region = _db.Region.FirstOrDefault(r => r.Uuid == region.ParentUuid.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4️⃣ 全部检查通过 → 床位可用
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/region/bed/create")]
|
[Route("api/region/bed/create")]
|
||||||
@@ -93,7 +122,7 @@ public class regionRoomBedController : ApiController
|
|||||||
{
|
{
|
||||||
return BadRequest("當前客房不存在");
|
return BadRequest("當前客房不存在");
|
||||||
}
|
}
|
||||||
if(room.Gender != bed.Gender)
|
if (room.Gender != bed.Gender)
|
||||||
{
|
{
|
||||||
return BadRequest("床為性別和房間性別必須一致");
|
return BadRequest("床為性別和房間性別必須一致");
|
||||||
}
|
}
|
||||||
@@ -105,7 +134,7 @@ public class regionRoomBedController : ApiController
|
|||||||
{
|
{
|
||||||
Name = bed.Name,
|
Name = bed.Name,
|
||||||
RoomUuid = bed.RoomUuid,
|
RoomUuid = bed.RoomUuid,
|
||||||
StatusUuid = bed.StatusUuid,
|
StatusCode = bed.StatusCode,
|
||||||
IsActive = bed.IsActive,
|
IsActive = bed.IsActive,
|
||||||
Gender = bed.Gender,
|
Gender = bed.Gender,
|
||||||
Uuid = Guid.NewGuid(),
|
Uuid = Guid.NewGuid(),
|
||||||
@@ -114,10 +143,11 @@ public class regionRoomBedController : ApiController
|
|||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
|
|
||||||
//創建床位
|
//創建床位
|
||||||
return Ok(new {
|
return Ok(new
|
||||||
|
{
|
||||||
uuid = regionBed.Uuid,
|
uuid = regionBed.Uuid,
|
||||||
roomUuid = regionBed.RoomUuid,
|
roomUuid = regionBed.RoomUuid,
|
||||||
statusuuid = regionBed.StatusUuid,
|
statuscode = regionBed.StatusCode,
|
||||||
isactive = regionBed.IsActive,
|
isactive = regionBed.IsActive,
|
||||||
gender = regionBed.Gender,
|
gender = regionBed.Gender,
|
||||||
name = regionBed.Name,
|
name = regionBed.Name,
|
||||||
@@ -146,7 +176,21 @@ public class regionRoomBedController : ApiController
|
|||||||
{
|
{
|
||||||
return BadRequest("床為性別和房間性別必須一致");
|
return BadRequest("床為性別和房間性別必須一致");
|
||||||
}
|
}
|
||||||
oldBed.StatusUuid = bed.StatusUuid;
|
if (bed.IsActive == false)
|
||||||
|
{
|
||||||
|
var hasPendingBeds = oldBed.GuaDanOrderGuest.Any(g => !g.IsDeleted &&
|
||||||
|
(g.RegionRoomBedStatus.Code == GuaDanOrderGuest.STATUS_BOOKED || // 预约中
|
||||||
|
g.RegionRoomBedStatus.Code == GuaDanOrderGuest.STATUS_CHECKED_IN));
|
||||||
|
if (hasPendingBeds)
|
||||||
|
{
|
||||||
|
return Content(HttpStatusCode.BadRequest, new
|
||||||
|
{
|
||||||
|
code = "BED_IS_USED",
|
||||||
|
message = "該床位正在掛單中,請先處理"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oldBed.StatusCode = bed.StatusCode;
|
||||||
oldBed.IsActive = bed.IsActive;
|
oldBed.IsActive = bed.IsActive;
|
||||||
oldBed.Name = bed.Name;
|
oldBed.Name = bed.Name;
|
||||||
oldBed.Gender = bed.Gender;
|
oldBed.Gender = bed.Gender;
|
||||||
@@ -157,25 +201,75 @@ public class regionRoomBedController : ApiController
|
|||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/region/bed/delete")]
|
[Route("api/region/bed/delete")]
|
||||||
public IHttpActionResult delete([FromUri] Guid uuid)
|
public IHttpActionResult Delete([FromUri] Guid uuid)
|
||||||
{
|
{
|
||||||
var bed = _db.RegionRoomBed.Find(uuid);
|
var bed = _db.RegionRoomBed.Find(uuid);
|
||||||
if (bed == null)
|
if (bed == null)
|
||||||
{
|
{
|
||||||
return BadRequest("未找到床位");
|
return BadRequest("未找到床位");
|
||||||
}
|
}
|
||||||
_db.RegionRoomBed.Remove(bed);
|
|
||||||
_db.SaveChanges();
|
try
|
||||||
return Ok(new { message = "刪除成功" });
|
{
|
||||||
|
_db.RegionRoomBed.Remove(bed);
|
||||||
|
_db.SaveChanges();
|
||||||
|
return Ok(new { message = "刪除成功" });
|
||||||
|
}
|
||||||
|
catch (System.Data.Entity.Infrastructure.DbUpdateException ex)
|
||||||
|
{
|
||||||
|
// 判斷是否為外鍵關聯錯誤
|
||||||
|
if (ex.InnerException?.InnerException is System.Data.SqlClient.SqlException sqlEx &&
|
||||||
|
(sqlEx.Number == 547)) // 547 = SQL Server 外鍵違反錯誤碼
|
||||||
|
{
|
||||||
|
return BadRequest("刪除失敗:該床位已被使用或存在關聯資料,無法刪除。");
|
||||||
|
}
|
||||||
|
|
||||||
|
return InternalServerError(ex); // 其他資料庫錯誤
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return InternalServerError(ex); // 其他未預期錯誤
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("api/region/bed/getavailablebedcountbytime")]
|
[Route("api/region/bed/getavailablebedcountbytime")]
|
||||||
public async Task<IHttpActionResult> GetCanUseBedCountByTime(DateTime startTime, DateTime endTime)
|
public async Task<IHttpActionResult> GetCanUseBedCountByTime(DateTime startTime, DateTime endTime)
|
||||||
{
|
{
|
||||||
//获取某个时间段内可用床位数量
|
//获取某个时间段内可用床位数量
|
||||||
var counts = await RegionAndRoomAndBedSchedule.GetAvailableBedCountsAsync(_db, startTime, endTime);
|
var start = startTime.Date;
|
||||||
return Ok(counts);
|
var end = endTime.Date;
|
||||||
|
|
||||||
|
// 找出所有在日期範圍內被占用的床位
|
||||||
|
var busyBedUuids = await _db.RegionAndRoomAndBedSchedule
|
||||||
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "403")
|
||||||
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "404")
|
||||||
|
.Where(a => a.IsCancel == false)
|
||||||
|
.Where(s => s.IsDeleted == false
|
||||||
|
&& (s.ScheduleDate == null // 長期占用
|
||||||
|
|| (s.ScheduleDate >= start && s.ScheduleDate < end)))
|
||||||
|
.Select(s => s.TargetUuid)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 可用床位 = 所有床位 - 忙碌床位
|
||||||
|
var availableBeds = _db.RegionRoomBed
|
||||||
|
.Where(b => b.IsActive)
|
||||||
|
.Where(b => !busyBedUuids.Contains(b.Uuid));
|
||||||
|
|
||||||
|
var result = await availableBeds
|
||||||
|
.GroupBy(b => b.Gender)
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
Gender = g.Key,
|
||||||
|
Count = g.Count()
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var male = result.Where(r => r.Gender == true).Select(r => r.Count).FirstOrDefault();
|
||||||
|
var female = result.Where(r => r.Gender == false).Select(r => r.Count).FirstOrDefault();
|
||||||
|
return Ok(new {male, female});
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@@ -260,7 +354,7 @@ public class regionRoomBedController : ApiController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(index < followers.Count)
|
if (index < followers.Count)
|
||||||
{
|
{
|
||||||
isAllallocation = false;
|
isAllallocation = false;
|
||||||
return;
|
return;
|
||||||
@@ -313,7 +407,7 @@ public class regionRoomBedController : ApiController
|
|||||||
{
|
{
|
||||||
// 先拉出床位相關排程到內存,避免 EF 不支援 .Date
|
// 先拉出床位相關排程到內存,避免 EF 不支援 .Date
|
||||||
var schedules = _db.RegionAndRoomAndBedSchedule
|
var schedules = _db.RegionAndRoomAndBedSchedule
|
||||||
.Where(s => s.IsDeleted == false && s.IsActive && s.TargetUuid == req.bedUuid)
|
.Where(s => s.IsDeleted == false && !s.IsCancel && s.TargetUuid == req.bedUuid)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
bool conflictExists = schedules.Any(s =>
|
bool conflictExists = schedules.Any(s =>
|
||||||
@@ -349,13 +443,14 @@ public class regionRoomBedController : ApiController
|
|||||||
RoomUuid = roomUuid,
|
RoomUuid = roomUuid,
|
||||||
CheckInAt = allocationStart,
|
CheckInAt = allocationStart,
|
||||||
CheckOutAt = allocationEnd,
|
CheckOutAt = allocationEnd,
|
||||||
|
StatusCode = "401",
|
||||||
};
|
};
|
||||||
_db.GuaDanOrderGuest.Add(guest);
|
_db.GuaDanOrderGuest.Add(guest);
|
||||||
|
|
||||||
// 新增每日排程
|
// 新增每日排程
|
||||||
if (allocationEnd.HasValue)
|
if (allocationEnd.HasValue)
|
||||||
{
|
{
|
||||||
for (var date = allocationStart; date <= allocationEnd.Value; date = date.AddDays(1))
|
for (var date = allocationStart; date < allocationEnd.Value; date = date.AddDays(1))
|
||||||
{
|
{
|
||||||
var newSchedule = new RegionAndRoomAndBedSchedule
|
var newSchedule = new RegionAndRoomAndBedSchedule
|
||||||
{
|
{
|
||||||
@@ -364,10 +459,11 @@ public class regionRoomBedController : ApiController
|
|||||||
ScheduleDate = date,
|
ScheduleDate = date,
|
||||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
IsActive = true,
|
|
||||||
CreatedBy = "系统自动分配",
|
CreatedBy = "系统自动分配",
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.Now,
|
||||||
GuaDanOrderNo = guest.GuaDanOrderNo
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||||
|
Title = "掛單",
|
||||||
|
GuaDanOrderGuestUuid = guest.Uuid,
|
||||||
};
|
};
|
||||||
_db.RegionAndRoomAndBedSchedule.Add(newSchedule);
|
_db.RegionAndRoomAndBedSchedule.Add(newSchedule);
|
||||||
}
|
}
|
||||||
@@ -382,10 +478,11 @@ public class regionRoomBedController : ApiController
|
|||||||
ScheduleDate = null,
|
ScheduleDate = null,
|
||||||
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
IsActive = true,
|
|
||||||
CreatedBy = "系统自动分配",
|
CreatedBy = "系统自动分配",
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.Now,
|
||||||
GuaDanOrderNo = guest.GuaDanOrderNo
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
||||||
|
Title = "掛單",
|
||||||
|
GuaDanOrderGuestUuid = guest.Uuid,
|
||||||
};
|
};
|
||||||
_db.RegionAndRoomAndBedSchedule.Add(newSchedule);
|
_db.RegionAndRoomAndBedSchedule.Add(newSchedule);
|
||||||
}
|
}
|
||||||
@@ -406,7 +503,7 @@ public class regionRoomBedController : ApiController
|
|||||||
|
|
||||||
private bool BedIsCanUsed(RegionRoomBed bed, DateTime? StartTime, DateTime? EndTime)
|
private bool BedIsCanUsed(RegionRoomBed bed, DateTime? StartTime, DateTime? EndTime)
|
||||||
{
|
{
|
||||||
if(!bed.IsActive)
|
if (!bed.IsActive)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Web.Http;
|
|||||||
/// regionRoomBedStatusController 的摘要描述
|
/// regionRoomBedStatusController 的摘要描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ezAuthorize]
|
[ezAuthorize]
|
||||||
public class regionRoomBedStatusController: ApiController
|
public class regionRoomBedStatusController : ApiController
|
||||||
{
|
{
|
||||||
private Model.ezEntities _db = new Model.ezEntities();
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
public regionRoomBedStatusController()
|
public regionRoomBedStatusController()
|
||||||
@@ -34,7 +34,6 @@ public class regionRoomBedStatusController: ApiController
|
|||||||
s.Code,
|
s.Code,
|
||||||
s.Name,
|
s.Name,
|
||||||
s.Description,
|
s.Description,
|
||||||
s.Uuid,
|
|
||||||
s.CategoryName
|
s.CategoryName
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
@@ -53,9 +52,9 @@ public class regionRoomBedStatusController: ApiController
|
|||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/region/bed/status/delete")]
|
[Route("api/region/bed/status/delete")]
|
||||||
public IHttpActionResult DeleteBedStatus([FromUri]Guid id)
|
public IHttpActionResult DeleteBedStatus([FromUri] string code)
|
||||||
{
|
{
|
||||||
var rt = _db.RegionRoomBedStatus.Find(id);
|
var rt = _db.RegionRoomBedStatus.Find(code);
|
||||||
if (rt == null)
|
if (rt == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.Data.Entity;
|
using System.Data.Entity;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.ServiceModel.Channels;
|
using System.ServiceModel.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
@@ -14,7 +15,7 @@ using static regionController;
|
|||||||
/// regionRoomController 的摘要描述
|
/// regionRoomController 的摘要描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ezAuthorize]
|
[ezAuthorize]
|
||||||
public class regionRoomController: ApiController
|
public class regionRoomController : ApiController
|
||||||
{
|
{
|
||||||
private Model.ezEntities _db = new Model.ezEntities();
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
public regionRoomController()
|
public regionRoomController()
|
||||||
@@ -38,6 +39,15 @@ public class regionRoomController: ApiController
|
|||||||
{
|
{
|
||||||
return BadRequest("請輸入床位數量");
|
return BadRequest("請輸入床位數量");
|
||||||
}
|
}
|
||||||
|
var region = _db.Region.Find(room.RegionUuid);
|
||||||
|
if(region == null)
|
||||||
|
{
|
||||||
|
return BadRequest("未找到客房所屬的區域");
|
||||||
|
}
|
||||||
|
if(region.Room.Count() >= region.RoomCount)
|
||||||
|
{
|
||||||
|
return BadRequest("當前區域客房數量已經達到上限");
|
||||||
|
}
|
||||||
var newRoom = new Room();
|
var newRoom = new Room();
|
||||||
newRoom.Name = room.Name;
|
newRoom.Name = room.Name;
|
||||||
newRoom.RegionUuid = room.RegionUuid;
|
newRoom.RegionUuid = room.RegionUuid;
|
||||||
@@ -62,7 +72,7 @@ public class regionRoomController: ApiController
|
|||||||
name = c.Name,
|
name = c.Name,
|
||||||
roomUuid = c.RoomUuid,
|
roomUuid = c.RoomUuid,
|
||||||
isactive = c.IsActive,
|
isactive = c.IsActive,
|
||||||
statusuuid = c.StatusUuid,
|
statuscode = c.StatusCode,
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -86,10 +96,27 @@ public class regionRoomController: ApiController
|
|||||||
// 如果有不符合性別的床位,不能繼續操作
|
// 如果有不符合性別的床位,不能繼續操作
|
||||||
return BadRequest("房間中已有與房間性別不符的床位,無法操作");
|
return BadRequest("房間中已有與房間性別不符的床位,無法操作");
|
||||||
}
|
}
|
||||||
if(!room.BedCount.HasValue)
|
if (!room.BedCount.HasValue)
|
||||||
{
|
{
|
||||||
return BadRequest("請輸入床位數量");
|
return BadRequest("請輸入床位數量");
|
||||||
}
|
}
|
||||||
|
if (room.IsActive == false)
|
||||||
|
{
|
||||||
|
var hasPendingBeds = oldRoom.RegionRoomBed
|
||||||
|
.SelectMany(b => b.GuaDanOrderGuest)
|
||||||
|
.Any(g => !g.IsDeleted &&
|
||||||
|
(g.RegionRoomBedStatus.Code == GuaDanOrderGuest.STATUS_BOOKED || // 预约中
|
||||||
|
g.RegionRoomBedStatus.Code == GuaDanOrderGuest.STATUS_CHECKED_IN)); // 已入住
|
||||||
|
if (hasPendingBeds)
|
||||||
|
{
|
||||||
|
return Content(HttpStatusCode.BadRequest, new
|
||||||
|
{
|
||||||
|
code = "BED_IS_USED",
|
||||||
|
message = "該房间有床位正在掛單中,請先處理"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
oldRoom.Name = room.Name;
|
oldRoom.Name = room.Name;
|
||||||
oldRoom.BedCount = room.BedCount;
|
oldRoom.BedCount = room.BedCount;
|
||||||
oldRoom.Gender = room.Gender;
|
oldRoom.Gender = room.Gender;
|
||||||
@@ -97,21 +124,49 @@ public class regionRoomController: ApiController
|
|||||||
oldRoom.IsActive = room.IsActive;
|
oldRoom.IsActive = room.IsActive;
|
||||||
oldRoom.RegionUuid = room.RegionUuid;
|
oldRoom.RegionUuid = room.RegionUuid;
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
return Ok(new { message = "更新成功"});
|
return Ok(new { message = "更新成功" });
|
||||||
}
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/region/room/delete")]
|
[Route("api/region/room/delete")]
|
||||||
public async Task<IHttpActionResult> deleteRoom([FromBody] Room rm)
|
public async Task<IHttpActionResult> deleteRoom([FromBody] Room rm)
|
||||||
{
|
{
|
||||||
var room = await _db.Room.FindAsync(rm.Uuid);
|
using (var transaction = _db.Database.BeginTransaction())
|
||||||
if (room == null) return BadRequest("房間不存在");
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var room = await _db.Room.FindAsync(rm.Uuid);
|
||||||
|
if (room == null) return BadRequest("房間不存在");
|
||||||
|
|
||||||
var beds = _db.RegionRoomBed.Where(b => b.RoomUuid == room.Uuid);
|
var beds = _db.RegionRoomBed.Where(b => b.RoomUuid == room.Uuid);
|
||||||
_db.RegionRoomBed.RemoveRange(beds);
|
_db.RegionRoomBed.RemoveRange(beds);
|
||||||
|
|
||||||
_db.Room.Remove(room);
|
_db.Room.Remove(room);
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
return Ok(new { message = "刪除成功" });
|
await _db.SaveChangesAsync();
|
||||||
|
transaction.Commit();
|
||||||
|
|
||||||
|
return Ok(new { message = "刪除成功" });
|
||||||
|
}
|
||||||
|
catch (System.Data.Entity.Infrastructure.DbUpdateException ex)
|
||||||
|
{
|
||||||
|
transaction.Rollback();
|
||||||
|
|
||||||
|
// 判断是否为外键约束错误
|
||||||
|
if (ex.InnerException?.InnerException is System.Data.SqlClient.SqlException sqlEx &&
|
||||||
|
sqlEx.Number == 547) // 547 = 外键冲突
|
||||||
|
{
|
||||||
|
return BadRequest("房間或床位正在被使用,不能刪除");
|
||||||
|
}
|
||||||
|
|
||||||
|
return InternalServerError(ex);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
transaction.Rollback();
|
||||||
|
return InternalServerError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
:server-items-length="activity_statistics.totalItems"
|
:server-items-length="activity_statistics.totalItems"
|
||||||
:items="activity_statistics.items">
|
:items="activity_statistics.items">
|
||||||
<template #item.detail_btn="{item}">
|
<template #item.detail_btn="{item}">
|
||||||
<a :href="'activity.aspx?num='+item.id" class="btn btn-outline-secondary btn-sm" target="_blank">詳細統計</a>
|
<a :href="'statistics.aspx?num='+item.id + '&activity_name=' + encodeURIComponent(item.activity_name)" class="btn btn-outline-secondary btn-sm" target="_blank">詳細統計</a>
|
||||||
</template>
|
</template>
|
||||||
<template #item.duetime="{item}">
|
<template #item.duetime="{item}">
|
||||||
{{item.startdate|timeString("YYYY/MM/DD")}}-{{item.enddate|timeString("YYYY/MM/DD")}}
|
{{item.startdate|timeString("YYYY/MM/DD")}}-{{item.enddate|timeString("YYYY/MM/DD")}}
|
||||||
|
|||||||
186
web/admin/activity/statistics/statistics.aspx
Normal file
186
web/admin/activity/statistics/statistics.aspx
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="statistics.aspx.cs" Inherits="admin_activity_statistics_statistics" %>
|
||||||
|
|
||||||
|
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||||
|
</asp:Content>
|
||||||
|
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||||
|
<div class="ms-5">
|
||||||
|
<span>
|
||||||
|
活動名稱: {{ activity_name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="me-5">
|
||||||
|
<button class="btn btn-primary" type="button">匯出表格資料</button>
|
||||||
|
</div>
|
||||||
|
</asp:Content>
|
||||||
|
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||||
|
<div id="content" class="container-fluid">
|
||||||
|
<div class="card shadow-sm my-2" id="sec2">
|
||||||
|
<div class="card-header py-0">
|
||||||
|
<nav class="navbar py-0">
|
||||||
|
<div class="nav nav-tabs">
|
||||||
|
<button class="nav-link active" id="sec2-tab1" data-bs-toggle="tab" data-bs-target="#sec2-page1"
|
||||||
|
type="button" role="tab" aria-controls="home" aria-selected="true">
|
||||||
|
活動統計總表</button>
|
||||||
|
<button class="nav-link" id="sec2-tab2" data-bs-toggle="tab" data-bs-target="#sec2-page2"
|
||||||
|
type="button" role="tab" aria-controls="profile" aria-selected="false">
|
||||||
|
活動統計數量明細 </button>
|
||||||
|
<button class="nav-link" id="sec2-tab3" data-bs-toggle="tab" data-bs-target="#sec2-page3"
|
||||||
|
type="button" role="tab" aria-controls="profile" aria-selected="false">
|
||||||
|
活動統計報名人明細 </button>
|
||||||
|
<button class="nav-link" id="sec2-tab4" data-bs-toggle="tab" data-bs-target="#sec2-page4"
|
||||||
|
type="button" role="tab" aria-controls="profile" aria-selected="false">
|
||||||
|
活動牌位明細</button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div class="tab-content" id="myTabContent">
|
||||||
|
<div class="tab-pane fade show active noedit p-4" id="sec2-page1" role="tabpanel" aria-labelledby="sec2-tab1">
|
||||||
|
<h5 class="mb-4"> {{ activity_name }}(截至 {{summaryStats?.reportDate }})</h5>
|
||||||
|
<!-- 基本資訊 + 功德金 統計 -->
|
||||||
|
<table class="table table-bordered table-sm w-auto mb-4">
|
||||||
|
<tbody>
|
||||||
|
<!-- 基本資訊 -->
|
||||||
|
<tr class="table-primary">
|
||||||
|
<th colspan="4">基本資訊</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>類別</th>
|
||||||
|
<td>報名人數</td>
|
||||||
|
<td>男眾人數</td>
|
||||||
|
<td>女眾人數</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>數量</th>
|
||||||
|
<td>{{ summaryStats?.totalApplicants }}</td>
|
||||||
|
<td>{{ summaryStats?.maleApplicants }}</td>
|
||||||
|
<td>{{ summaryStats?.femaleApplicants }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="table table-bordered table-sm w-auto mb-4">
|
||||||
|
<tbody>
|
||||||
|
<!-- 功德金 -->
|
||||||
|
<tr class="table-primary">
|
||||||
|
<th colspan="4">功德金統計</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>類別</th>
|
||||||
|
<td>總功德金</td>
|
||||||
|
<td>已收</td>
|
||||||
|
<td>未收</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>金額</th>
|
||||||
|
<td>{{ summaryStats?.donation.total }}</td>
|
||||||
|
<td>{{ summaryStats?.donation.received }}</td>
|
||||||
|
<td>{{ summaryStats?.donation.unreceived }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<!-- 功德項目 -->
|
||||||
|
<table class="table table-bordered table-sm w-auto mb-4">
|
||||||
|
<tbody>
|
||||||
|
<tr class="table-primary">
|
||||||
|
<th colspan="100%">功德項目</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>功德項目</th>
|
||||||
|
<td v-for="(item, index) in summaryStats?.items" :key="'name-' + index">
|
||||||
|
{{ item.name }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>人數</th>
|
||||||
|
<td v-for="(item, index) in summaryStats?.items" :key="'count-' + index">
|
||||||
|
{{ item.count }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- 牌位數量 -->
|
||||||
|
<table class="table table-bordered table-sm w-auto">
|
||||||
|
<tbody>
|
||||||
|
<tr class="table-primary">
|
||||||
|
<th colspan="100%">牌位數量</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>牌位名稱</th>
|
||||||
|
<td v-for="(plaque, index) in summaryStats?.plaques" :key="'plaque-name-' + index">
|
||||||
|
{{ plaque.name }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>數量</th>
|
||||||
|
<td v-for="(plaque, index) in summaryStats?.plaques" :key="'plaque-count-' + index">
|
||||||
|
{{ plaque.count }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane fade" id="sec2-page2" role="tabpanel" aria-labelledby="sec2-tab2">
|
||||||
|
sec2-page2
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade" id="sec2-page3" role="tabpanel" aria-labelledby="sec2-tab3">
|
||||||
|
sec2-page3
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade" id="sec2-page4" role="tabpanel" aria-labelledby="sec2-tab4">
|
||||||
|
sec2-page4
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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 {
|
||||||
|
activity_num: '<%= Request["num"] %>',
|
||||||
|
activity_name: '<%= Request["activity_name"] %>',
|
||||||
|
summaryStats: null, //匯總統計(總覽)
|
||||||
|
quantityDetails: [], // 數量明細(分類數量)
|
||||||
|
applicantList: [], // 報名人清單
|
||||||
|
plaqueList: [], //牌位清單
|
||||||
|
loadingSummary: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchSummaryStats() {
|
||||||
|
//獲取匯總明細
|
||||||
|
this.loadingSummary = true;
|
||||||
|
|
||||||
|
axios.get(HTTP_HOST + 'api/activity/statistics/summary',
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
activity_num: this.activity_num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
this.summaryStats = res.data;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loadingSummary = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetchSummaryStats(); // 頁面載入時就獲取
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</asp:Content>
|
||||||
|
|
||||||
14
web/admin/activity/statistics/statistics.aspx.cs
Normal file
14
web/admin/activity/statistics/statistics.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_activity_statistics_statistics : MyWeb.config
|
||||||
|
{
|
||||||
|
protected void Page_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,8 +103,8 @@ public partial class admin_follower_reg : MyWeb.config
|
|||||||
|
|
||||||
if (prod.birthday.HasValue)
|
if (prod.birthday.HasValue)
|
||||||
{
|
{
|
||||||
Literal1.Text = publicFun.chagenDate(prod.birthday.Value);
|
Literal1.Text = publicFun.chagenDate(prod.birthday.Value); //農曆生日
|
||||||
Literal2.Text = Model.follower.chagenSign(prod.birthday.Value);
|
Literal2.Text = Model.follower.chagenSign(prod.birthday.Value); //生肖
|
||||||
}
|
}
|
||||||
if (prod.leader.HasValue)
|
if (prod.leader.HasValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,15 @@
|
|||||||
<div class="col-sm-4 text-left">
|
<div class="col-sm-4 text-left">
|
||||||
<input class="form-control" v-model="guadanorder.order_form.orderNo" readonly />
|
<input class="form-control" v-model="guadanorder.order_form.orderNo" readonly />
|
||||||
</div>
|
</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>
|
||||||
<div class="form-group row mt-3">
|
<div class="form-group row mt-3">
|
||||||
<label class="col-sm-2 col-form-label text-center">
|
<label class="col-sm-2 col-form-label text-center">
|
||||||
@@ -85,17 +94,105 @@
|
|||||||
<template v-slot:item.name="{item}">
|
<template v-slot:item.name="{item}">
|
||||||
{{item.follower?.u_name}}
|
{{item.follower?.u_name}}
|
||||||
</template>
|
</template>
|
||||||
<template #item.actions="{ item }">
|
<template v-slot:item.sex="{item}">
|
||||||
<v-btn color="red" variant="outlined" size="small" class="me-2" @click="confirmDeleteGuadanOrderGuest(item)">
|
{{item.follower?.sex}}
|
||||||
取消
|
|
||||||
</v-btn>
|
|
||||||
<v-btn color="primary" variant="outlined" size="small" @click="editGuadanOrderGuest(item)">
|
|
||||||
<v-icon start>mdi-pencil</v-icon>
|
|
||||||
編輯
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #item.actions="{ item }">
|
||||||
|
<div>
|
||||||
|
<!-- 取消預訂 -->
|
||||||
|
<v-btn
|
||||||
|
color="red"
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
class="me-2"
|
||||||
|
:disabled="item.statuscode !== '401'"
|
||||||
|
@click="confirmDeleteGuadanOrderGuest(item)"
|
||||||
|
>
|
||||||
|
取消預訂
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="red"
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
class="me-2"
|
||||||
|
:disabled="item.statuscode !== '401'"
|
||||||
|
@click="checkinGuadanGuest(item)"
|
||||||
|
>
|
||||||
|
入住
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="red"
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
class="me-2"
|
||||||
|
:disabled="item.statuscode !== '402'"
|
||||||
|
@click="showXuzhuGuestModalMethod(item)">
|
||||||
|
續住
|
||||||
|
</v-btn>
|
||||||
|
<!-- 退房 -->
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
:disabled="item.statuscode !== '402'"
|
||||||
|
@click="checkoutGuadanOrderGuest(item)"
|
||||||
|
>
|
||||||
|
<v-icon start>mdi-exit-run</v-icon>
|
||||||
|
退房
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<!-- 🟢 續住彈出視窗 -->
|
||||||
|
<div>
|
||||||
|
<v-dialog v-model="guadanguest.xuzhu.showXuzhuGuestModal" max-width="50%">
|
||||||
|
<v-card
|
||||||
|
class="pa-6 d-flex flex-column" style="min-height: 60vh; border-radius: 12px;"
|
||||||
|
style="min-height: 40vh; border-radius: 12px; box-shadow: 0 8px 20px rgba(0,0,0,0.15);"
|
||||||
|
>
|
||||||
|
<!-- 弹窗标题 -->
|
||||||
|
<v-card-title
|
||||||
|
class="text-h6 d-flex align-center justify-space-between pb-4"
|
||||||
|
style="border-bottom: 1px solid #eee;"
|
||||||
|
>
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<span class="font-weight-bold">续住</span>
|
||||||
|
</div>
|
||||||
|
<v-btn icon @click="closeXuzhuGuestModalMethod">
|
||||||
|
<v-icon>mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-card-title>
|
||||||
|
|
||||||
|
<!-- 弹窗内容 -->
|
||||||
|
<v-card-text class="flex-grow-1 py-6" style="overflow-y: auto;">
|
||||||
|
<div class="mb-4">
|
||||||
|
<span class="font-weight-medium">当前退房时间:</span>
|
||||||
|
<span class="text-primary">{{ guadanguest.xuzhu.currentCheckoutDate }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<span class="font-weight-medium mr-2">续住后退房时间:</span>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
id="newCheckoutDate"
|
||||||
|
v-model="guadanguest.xuzhu.newCheckoutDate"
|
||||||
|
class="pa-2"
|
||||||
|
style="border: 1px solid #ccc; border-radius: 6px; padding: 6px 10px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<!-- 弹窗操作按钮 -->
|
||||||
|
<v-card-actions class="justify-end pt-4" style="border-top: 1px solid #eee;">
|
||||||
|
<v-btn color="primary" class="px-6" @click="xuzhuPost">续住</v-btn>
|
||||||
|
<v-btn text class="ml-2" @click="closeXuzhuGuestModalMethod">取消</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 🟢 掛單蓮友彈出視窗 -->
|
<!-- 🟢 掛單蓮友彈出視窗 -->
|
||||||
<div>
|
<div>
|
||||||
@@ -174,21 +271,6 @@
|
|||||||
<div class="text-info text-xs mt-1">請從床位清單中選擇</div>
|
<div class="text-info text-xs mt-1">請從床位清單中選擇</div>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" sm="6">
|
|
||||||
<div class="d-flex flex-column justify-center" style="height: 100%;">
|
|
||||||
<v-select
|
|
||||||
v-model="checkInGuest.inGuest.statusUuid"
|
|
||||||
:items="checkInGuest.status"
|
|
||||||
item-value="uuid"
|
|
||||||
item-text="name"
|
|
||||||
label="选择個人挂单状态"
|
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
></v-select>
|
|
||||||
</div>
|
|
||||||
</v-col>
|
|
||||||
|
|
||||||
|
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@@ -247,13 +329,13 @@
|
|||||||
<div v-for="bed in region_modal.currentSelectBeds" :key="bed.uuid" @click="selectBed(bed)" style="padding: 8px; border: 1px solid #d9d9d9; cursor: pointer; max-height: 250px;" :style="{
|
<div v-for="bed in region_modal.currentSelectBeds" :key="bed.uuid" @click="selectBed(bed)" style="padding: 8px; border: 1px solid #d9d9d9; cursor: pointer; max-height: 250px;" :style="{
|
||||||
backgroundColor: region_modal.currentSelectBed?.uuid === bed.uuid
|
backgroundColor: region_modal.currentSelectBed?.uuid === bed.uuid
|
||||||
? '#bae7ff' // 當前選中
|
? '#bae7ff' // 當前選中
|
||||||
: (bed.canUsed ? '#f6ffed' : '#fff1f0'), // 可用綠色,不可用紅色
|
: ((bed.canUsed && bed.isActive && !bed.bedIsStop) ? '#f6ffed' : '#fff1f0'), // 可用綠色,不可用紅色
|
||||||
color: bed.canUsed ? 'black' : '#999', // 不可用時灰色文字
|
color: (bed.canUsed && bed.isActive && !bed.bedIsStop) ? 'black' : '#999', // 不可用時灰色文字
|
||||||
pointerEvents: bed.canUsed ? 'auto' : 'none' // 不可用時無法點擊
|
pointerEvents: (bed.canUsed && bed.isActive && !bed.bedIsStop) ? 'auto' : 'none' // 不可用時無法點擊
|
||||||
}">
|
}">
|
||||||
<div style="font-weight: 500;">{{ bed.name }}</div>
|
<div style="font-weight: 500;">{{ bed.name }}</div>
|
||||||
<div style="margin-top: 4px; font-size: 12px;">
|
<div style="margin-top: 4px; font-size: 12px;">
|
||||||
{{ bed.canUsed ? '可用' : '不可用' }}
|
{{ (!bed.isActive || bed.bedIsStop) ? '停用' : (bed.canUsed ? '可用' : '不可用') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -768,6 +850,7 @@
|
|||||||
vuetify: new Vuetify(vuetify_options),
|
vuetify: new Vuetify(vuetify_options),
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
activityList: [],
|
||||||
availableBedCount: {
|
availableBedCount: {
|
||||||
male: 0,
|
male: 0,
|
||||||
female: 0,
|
female: 0,
|
||||||
@@ -782,6 +865,7 @@
|
|||||||
bookerName: null,
|
bookerName: null,
|
||||||
bookerPhone: null,
|
bookerPhone: null,
|
||||||
bookerFollowerNum: null,
|
bookerFollowerNum: null,
|
||||||
|
activityNum: null,
|
||||||
},
|
},
|
||||||
status_items: [],
|
status_items: [],
|
||||||
},
|
},
|
||||||
@@ -804,6 +888,10 @@
|
|||||||
text: '姓名',
|
text: '姓名',
|
||||||
value: 'name'
|
value: 'name'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: '性別',
|
||||||
|
value: 'sex'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: '掛單開始時間',
|
text: '掛單開始時間',
|
||||||
value: 'checkinat'
|
value: 'checkinat'
|
||||||
@@ -812,10 +900,6 @@
|
|||||||
text: '掛單結束時間',
|
text: '掛單結束時間',
|
||||||
value: 'checkoutat'
|
value: 'checkoutat'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
text: '房間',
|
|
||||||
value: 'roomName'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
text: '床位',
|
text: '床位',
|
||||||
value: 'bedName'
|
value: 'bedName'
|
||||||
@@ -835,6 +919,13 @@
|
|||||||
],
|
],
|
||||||
items: [],
|
items: [],
|
||||||
showCreateGuestModal: false,
|
showCreateGuestModal: false,
|
||||||
|
xuzhu: {
|
||||||
|
showXuzhuGuestModal: false,
|
||||||
|
currentCheckoutDate: null,
|
||||||
|
newCheckoutDate: null,
|
||||||
|
guestUuid: null,
|
||||||
|
guestBedUuid: null,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
checkInGuest: {
|
checkInGuest: {
|
||||||
showSelectGuadanOrderGuest: false,
|
showSelectGuadanOrderGuest: false,
|
||||||
@@ -848,7 +939,7 @@
|
|||||||
bedUuid: null,
|
bedUuid: null,
|
||||||
checkInAt: null,
|
checkInAt: null,
|
||||||
checkOutAt: null,
|
checkOutAt: null,
|
||||||
statusUuid: null,
|
statuscode: null,
|
||||||
},
|
},
|
||||||
status: [],
|
status: [],
|
||||||
},
|
},
|
||||||
@@ -938,8 +1029,97 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
//续住相關方法--------------------start
|
||||||
|
showXuzhuGuestModalMethod(guest) {
|
||||||
|
if (!guest.checkoutat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.guadanguest.xuzhu.showXuzhuGuestModal = true;
|
||||||
|
this.guadanguest.xuzhu.currentCheckoutDate = guest.checkoutat;
|
||||||
|
this.guadanguest.xuzhu.guestUuid = guest.uuid;
|
||||||
|
this.guadanguest.xuzhu.guestBedUuid = guest.bedUuid;
|
||||||
|
|
||||||
|
this.$nextTick(() => { // 确保弹窗 DOM 已渲染
|
||||||
|
const input = document.getElementById('newCheckoutDate');
|
||||||
|
if (input) {
|
||||||
|
const checkoutDate = new Date(guest.checkoutat); // 用指定日期
|
||||||
|
checkoutDate.setDate(checkoutDate.getDate() + 1); // 明天
|
||||||
|
const year = checkoutDate.getFullYear();
|
||||||
|
const month = String(checkoutDate.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(checkoutDate.getDate()).padStart(2, '0');
|
||||||
|
const tomorrow = `${year}-${month}-${day}`;
|
||||||
|
input.min = tomorrow; // 限制最小值
|
||||||
|
//input.value = tomorrow; // 默认选中明天
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(guest.checkoutat)
|
||||||
|
},
|
||||||
|
closeXuzhuGuestModalMethod() {
|
||||||
|
console.log(this.guadanguest.xuzhu.newCheckoutDate)
|
||||||
|
this.guadanguest.xuzhu.showXuzhuGuestModal = false;
|
||||||
|
this.guadanguest.xuzhu.currentCheckoutDate = null;
|
||||||
|
this.guadanguest.xuzhu.newCheckoutDate = null;
|
||||||
|
this.guadanguest.xuzhu.guestUuid = null;
|
||||||
|
this.guadanguest.xuzhu.guestBedUuid = null;
|
||||||
|
console.log(this.guadanguest.xuzhu.newCheckoutDate)
|
||||||
|
console.log(this.guadanguest.xuzhu.currentCheckoutDate)
|
||||||
|
console.log(this.guadanguest.xuzhu.guestUuid)
|
||||||
|
console.log(this.guadanguest.xuzhu.guestBedUuid)
|
||||||
|
},
|
||||||
|
xuzhuPost() {
|
||||||
|
// 校验必填
|
||||||
|
if (!this.guadanguest.xuzhu.guestUuid || !this.guadanguest.xuzhu.guestBedUuid) {
|
||||||
|
alert("GuestUuid 和 GuestBedUuid 不能为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.guadanguest.xuzhu.newCheckoutDate || !this.guadanguest.xuzhu.currentCheckoutDate) {
|
||||||
|
alert("续住时间不能为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
guestUuid: this.guadanguest.xuzhu.guestUuid,
|
||||||
|
guestBedUuid: this.guadanguest.xuzhu.guestBedUuid,
|
||||||
|
currentCheckoutDate: this.guadanguest.xuzhu.currentCheckoutDate,
|
||||||
|
newCheckoutDate: this.guadanguest.xuzhu.newCheckoutDate
|
||||||
|
};
|
||||||
|
|
||||||
|
axios.post('/api/guadanorderguest/xuzhu', payload)
|
||||||
|
.then((res) => {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
title: '续住成功',
|
||||||
|
message: '客人续住已处理',
|
||||||
|
status: 'success',
|
||||||
|
callback: () => {
|
||||||
|
// 弹窗关闭后的回调
|
||||||
|
try {
|
||||||
|
this.getGuadanOrderGuestByOrderNo();
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("发生错误:", error.message);
|
||||||
|
} finally {
|
||||||
|
this.closeXuzhuGuestModalMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
title: '续住失败',
|
||||||
|
message: error.response?.data?.message || '系统异常,请稍后重试',
|
||||||
|
status: 'error'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//续住相關方法--------------------end
|
||||||
|
getActivityList() {
|
||||||
|
axios.post('/api/activity/GetList?page=1&pageSize=500', { kind: 0, subject: "" })
|
||||||
|
.then((res) => {
|
||||||
|
this.activityList = res.data.list
|
||||||
|
})
|
||||||
|
},
|
||||||
getavailablebedcountbytime(startTime, endTime) {
|
getavailablebedcountbytime(startTime, endTime) {
|
||||||
axios.get('/api/region/bed/getavailablebedcountbytime',{
|
axios.get('/api/region/bed/getavailablebedcountbytime', {
|
||||||
params: {
|
params: {
|
||||||
startTime: startTime,
|
startTime: startTime,
|
||||||
endTime: endTime
|
endTime: endTime
|
||||||
@@ -970,6 +1150,10 @@
|
|||||||
.then(res => {
|
.then(res => {
|
||||||
this.resetAutomaticBedAllocation();
|
this.resetAutomaticBedAllocation();
|
||||||
this.getGuadanOrderGuestByOrderNo();
|
this.getGuadanOrderGuestByOrderNo();
|
||||||
|
}).catch((error) => {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
message: (error.response?.data?.message || error.message)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -1117,6 +1301,7 @@
|
|||||||
this.guadanorder.order_form.bookerPhone = res.data.bookerPhone;
|
this.guadanorder.order_form.bookerPhone = res.data.bookerPhone;
|
||||||
this.guadanorder.order_form.bookerFollowerNum = res.data.bookerFollowerNum;
|
this.guadanorder.order_form.bookerFollowerNum = res.data.bookerFollowerNum;
|
||||||
this.guadanorder.order_form.uuid = res.data.uuid;
|
this.guadanorder.order_form.uuid = res.data.uuid;
|
||||||
|
this.guadanorder.order_form.activityNum = res.data.activityNum;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1203,6 +1388,40 @@
|
|||||||
//掛單相關方法-------------------end
|
//掛單相關方法-------------------end
|
||||||
|
|
||||||
//增加蓮友方法-------------------start
|
//增加蓮友方法-------------------start
|
||||||
|
checkoutGuadanOrderGuest(guest) {
|
||||||
|
this.$refs.confirmModal.open({
|
||||||
|
message: `確定要將 ${guest.follower.u_name || ''} 退房嗎?`,
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`/api/guadanorderguest/checkout`, null, {
|
||||||
|
params: { uuid: guest.uuid }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 成功提示
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
title: '操作成功',
|
||||||
|
message: '退房成功!',
|
||||||
|
status: 'success'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新狀態並刷新資料
|
||||||
|
guest.statusCode = "403"; // 已退房
|
||||||
|
this.getGuadanOrderGuestByOrderNo();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
// 失敗提示
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
title: '操作失敗',
|
||||||
|
message: error.response?.data?.message || '退房過程中發生錯誤!',
|
||||||
|
status: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
resetInGuest() {
|
resetInGuest() {
|
||||||
this.checkInGuest.inGuest = {
|
this.checkInGuest.inGuest = {
|
||||||
uuid: null,
|
uuid: null,
|
||||||
@@ -1212,7 +1431,7 @@
|
|||||||
bedUuid: null,
|
bedUuid: null,
|
||||||
checkInAt: null,
|
checkInAt: null,
|
||||||
checkOutAt: null,
|
checkOutAt: null,
|
||||||
statusUuid: null,
|
statuscode: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
setInGuest() {
|
setInGuest() {
|
||||||
@@ -1284,8 +1503,7 @@
|
|||||||
getGuadanGuestStatus() {
|
getGuadanGuestStatus() {
|
||||||
axios.get('/api/region/bed/status/list')
|
axios.get('/api/region/bed/status/list')
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.checkInGuest.status = res.data.filter(item => item.category === 4);
|
this.checkInGuest.status = res.data.filter(item => item.category === 4 && item.code != '404');
|
||||||
console.log(this.checkInGuest.status);
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
//增加蓮友方法-------------------end
|
//增加蓮友方法-------------------end
|
||||||
@@ -1318,7 +1536,7 @@
|
|||||||
},
|
},
|
||||||
selectGuadanOrderGuest(guest) {
|
selectGuadanOrderGuest(guest) {
|
||||||
this.selectGuestModal.currentSelectedGuest = guest;
|
this.selectGuestModal.currentSelectedGuest = guest;
|
||||||
console.log('----------'+ guest)
|
console.log('----------' + guest)
|
||||||
this.selectGuestModal.fullNameText = guest.u_name;
|
this.selectGuestModal.fullNameText = guest.u_name;
|
||||||
this.checkInGuest.inGuest.followerNum = guest.num;
|
this.checkInGuest.inGuest.followerNum = guest.num;
|
||||||
this.selectGuestModal.showSelectGuestModal = false;
|
this.selectGuestModal.showSelectGuestModal = false;
|
||||||
@@ -1336,7 +1554,7 @@
|
|||||||
this.getCurrentSelectBedTextByBedId(guest.bedUuid);
|
this.getCurrentSelectBedTextByBedId(guest.bedUuid);
|
||||||
this.selectGuestModal.fullNameText = guest.follower?.u_name;
|
this.selectGuestModal.fullNameText = guest.follower?.u_name;
|
||||||
this.selectGuestModal.currentSelectedGuest = guest.follower;
|
this.selectGuestModal.currentSelectedGuest = guest.follower;
|
||||||
this.checkInGuest.inGuest.statusUuid = guest.statusUuid;
|
this.checkInGuest.inGuest.statuscode = guest.statuscode;
|
||||||
|
|
||||||
},
|
},
|
||||||
async saveEditGuadanOrderGuest() {
|
async saveEditGuadanOrderGuest() {
|
||||||
@@ -1352,9 +1570,14 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
deleteGuadanOrderGuest(guest) {
|
deleteGuadanOrderGuest(guest) {
|
||||||
axios.post('/api/guadanorderguest/delete?uuid=' + guest.uuid).then((res) => {
|
axios.post('/api/guadanorderguest/cancel?uuid=' + guest.uuid)
|
||||||
this.guadanguest.items = this.guadanguest.items.filter(i => i.uuid != guest.uuid);
|
.then((res) => {
|
||||||
})
|
this.guadanguest.items = this.guadanguest.items.filter(i => i.uuid != guest.uuid);
|
||||||
|
}).catch((error) => {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
message: (error.response?.data?.message || error.message)
|
||||||
|
})
|
||||||
|
});
|
||||||
},
|
},
|
||||||
confirmDeleteGuadanOrderGuest(guest) {
|
confirmDeleteGuadanOrderGuest(guest) {
|
||||||
this.$refs.confirmModal.open({
|
this.$refs.confirmModal.open({
|
||||||
@@ -1364,6 +1587,43 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
async checkinGuadanGuest(guest) {
|
||||||
|
// 先確認操作
|
||||||
|
this.$refs.confirmModal.open({
|
||||||
|
message: '確認入住?',
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
// 發送請求到後端 API
|
||||||
|
const response = await axios.post(`/api/guadanorderguest/checkin`, null, {
|
||||||
|
params: { uuid: guest.uuid }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 成功提示
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
title: '操作成功',
|
||||||
|
message: '入住成功!',
|
||||||
|
status: 'success'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新本地列表,修改狀態為已入住 (402)
|
||||||
|
guest.statusCode = "402";
|
||||||
|
|
||||||
|
// 如果需要刷新整個列表,也可以調用
|
||||||
|
this.getGuadanOrderGuestByOrderNo();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
// 失敗提示
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
title: '操作失敗',
|
||||||
|
message: error.response?.data?.message || '入住過程中發生錯誤!',
|
||||||
|
status: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
//蓮友選擇相關方法---------------end
|
//蓮友選擇相關方法---------------end
|
||||||
|
|
||||||
//床位選擇相關方法----------------start
|
//床位選擇相關方法----------------start
|
||||||
@@ -1532,6 +1792,7 @@
|
|||||||
this.loadRegions();
|
this.loadRegions();
|
||||||
this.getGuadanOrderStatus();
|
this.getGuadanOrderStatus();
|
||||||
this.getGuadanGuestStatus();
|
this.getGuadanGuestStatus();
|
||||||
|
this.getActivityList();
|
||||||
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|||||||
239
web/admin/guadan/guest/index.aspx
Normal file
239
web/admin/guadan/guest/index.aspx
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="admin_guadan_guest_index" %>
|
||||||
|
|
||||||
|
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||||
|
</asp:Content>
|
||||||
|
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||||
|
<nav class="search-bar">
|
||||||
|
<div class="form-item">
|
||||||
|
<label>姓名:</label>
|
||||||
|
<input v-model="search.searchName" type="text" placeholder="請輸入姓名">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-item">
|
||||||
|
<label>入住日期:</label>
|
||||||
|
<input v-model="search.searchCheckInDate" type="date">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-item">
|
||||||
|
<label>退房日期:</label>
|
||||||
|
<input type="date" v-model="search.searchCheckOutDate">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-item">
|
||||||
|
<label>入住日期區間:</label>
|
||||||
|
<input type="date" v-model="search.searchCheckInDateStart"> -
|
||||||
|
<input type="date" v-model="search.searchCheckInDateEnd">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-item">
|
||||||
|
<label>退房日期區間:</label>
|
||||||
|
<input type="date" v-model="search.searchCheckOutDateStart"> -
|
||||||
|
<input type="date" v-model="search.searchCheckOutDateEnd">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-item buttons">
|
||||||
|
<button @click="handleSearch" type="button">查詢</button>
|
||||||
|
<button type="button" @click="clearSearch">清除查詢條件</button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</asp:Content>
|
||||||
|
|
||||||
|
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||||
|
<div>
|
||||||
|
<v-data-table
|
||||||
|
:headers="headers"
|
||||||
|
:items="guests"
|
||||||
|
:options.sync="options"
|
||||||
|
:server-items-length="total"
|
||||||
|
:loading="loading"
|
||||||
|
hide-default-footer
|
||||||
|
class="elevation-1"
|
||||||
|
>
|
||||||
|
<template v-slot:top>
|
||||||
|
<v-toolbar flat>
|
||||||
|
<v-toolbar-title>入住人列表</v-toolbar-title>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
</v-toolbar>
|
||||||
|
</template>
|
||||||
|
<template #item.checkindate ="{item}">
|
||||||
|
{{item.checkindate|timeString('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
|
<template #item.checkoutdate ="{item}">
|
||||||
|
{{item.checkoutdate|timeString('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
|
<template #item.guadanorderno="{item}">
|
||||||
|
{{item.guadanorderno}}<a :href="'/admin/guadan/create.aspx?orderId='+item.guadanorderno" class="btn btn-outline-primary">查看掛單</a>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
<v-container>
|
||||||
|
<v-row class="align-baseline" wrap>
|
||||||
|
<v-col cols="12" md="9">
|
||||||
|
<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-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">
|
||||||
|
<style>
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
background: #f9f9f9;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding: 4px 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 6px 14px;
|
||||||
|
background: #409eff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #66b1ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<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 {
|
||||||
|
loading: false,
|
||||||
|
search: {
|
||||||
|
searchName: null,
|
||||||
|
searchCheckInDateStart: null,//入住日期開始
|
||||||
|
searchCheckInDateEnd: null,//入住日期的結束
|
||||||
|
searchCheckOutDateStart: null,//退房日期的開始
|
||||||
|
searchCheckOutDateEnd: null,//退房日期的結束
|
||||||
|
searchCheckInDate: null,
|
||||||
|
searchCheckOutDate: null,
|
||||||
|
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
page: 1, // 當前頁
|
||||||
|
itemsPerPage: 10, // 每頁條數
|
||||||
|
sortBy: [],
|
||||||
|
sortDesc: []
|
||||||
|
},
|
||||||
|
headers: [
|
||||||
|
{ text: '姓名', value: 'name' },
|
||||||
|
{ text: '掛單單號', value: 'guadanorderno' },
|
||||||
|
{ text: '入住日期', value: 'checkindate' },
|
||||||
|
{ text: '退房日期', value: 'checkoutdate' },
|
||||||
|
{ text: '房間號', value: 'roomName' },
|
||||||
|
{ text: '狀態', value: 'statusName'},
|
||||||
|
|
||||||
|
],
|
||||||
|
guests: [], // 表格數據
|
||||||
|
total: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
resetTableOptions() {
|
||||||
|
this.options = {
|
||||||
|
page: 1,
|
||||||
|
itemsPerPage: 10,
|
||||||
|
sortBy: [],
|
||||||
|
sortDesc: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleSearch() {
|
||||||
|
this.resetTableOptions();
|
||||||
|
},
|
||||||
|
clearSearch() {
|
||||||
|
this.search.searchName = null;
|
||||||
|
this.search.searchCheckInDate = null;
|
||||||
|
this.search.searchCheckOutDate = null;
|
||||||
|
this.search.searchCheckInDateStart = null;
|
||||||
|
this.search.searchCheckInDateEnd = null;
|
||||||
|
this.search.searchCheckOutDateStart = null;
|
||||||
|
this.search.searchCheckOutDateEnd = null;
|
||||||
|
this.resetTableOptions();
|
||||||
|
},
|
||||||
|
fetchGuests() {
|
||||||
|
if (this.search.searchName && this.search.searchName.includes(' ')) {
|
||||||
|
alert('搜索內容不能包含空格');
|
||||||
|
return; // 阻止繼續執行
|
||||||
|
}
|
||||||
|
if (this.loading) return;
|
||||||
|
this.loading = true;
|
||||||
|
axios.post('/api/guadan/guest/query/list',
|
||||||
|
{
|
||||||
|
page: this.options.page,
|
||||||
|
pageSize: this.options.itemsPerPage,
|
||||||
|
searchName: this.search.searchName,
|
||||||
|
searchCheckInDate: this.search.searchCheckInDate,
|
||||||
|
searchCheckOutDate: this.search.searchCheckOutDate,
|
||||||
|
searchCheckInDateStart: this.search.searchCheckInDateStart,
|
||||||
|
searchCheckInDateEnd: this.search.searchCheckInDateEnd,
|
||||||
|
searchCheckOutDateStart: this.search.searchCheckOutDateStart,
|
||||||
|
searchCheckOutDateEnd: this.search.searchCheckOutDateEnd,
|
||||||
|
|
||||||
|
}).then(res => {
|
||||||
|
this.guests = res.data.items; // 數據
|
||||||
|
this.total = res.data.total; // 總數
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
options: {
|
||||||
|
handler() {
|
||||||
|
this.fetchGuests(); // 監聽分頁、排序變化,自動載入數據
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
pageCount() {
|
||||||
|
return Math.ceil(this.total / this.options.itemsPerPage)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</asp:Content>
|
||||||
14
web/admin/guadan/guest/index.aspx.cs
Normal file
14
web/admin/guadan/guest/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_guadan_guest_index : MyWeb.config
|
||||||
|
{
|
||||||
|
protected void Page_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,16 +6,45 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<a href="create.aspx" class="btn btn-primary" >新建掛單</a>
|
<a href="create.aspx" class="btn btn-primary" >新建掛單</a>
|
||||||
</nav>
|
</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" />
|
||||||
|
|
||||||
|
<label class="mb-0">開始時間</label>
|
||||||
|
<input class="form-control w-auto" style="width:150px;" type="date" v-model="search.startDate" />
|
||||||
|
|
||||||
|
<label class="mb-0">結束時間</label>
|
||||||
|
<input class="form-control w-auto" style="width:150px;" type="date" v-model="search.endDate" />
|
||||||
|
|
||||||
|
<button class="btn btn-primary" type="button" @click="handleSearch">查詢</button>
|
||||||
|
<button class="btn btn-outline-primary" type="button" @click="clearSearch">清除條件</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||||
|
|
||||||
<div class="mx-5">
|
<div class="mx-5">
|
||||||
<v-data-table
|
<v-data-table
|
||||||
:items="items"
|
:items="items"
|
||||||
:headers="headers">
|
:headers="headers"
|
||||||
|
:item-class="item => item.is_timeout ? 'row-timeout' : ''"
|
||||||
|
hide-default-footer>
|
||||||
<template #item.actions="{item}">
|
<template #item.actions="{item}">
|
||||||
<a :href="'create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-secondary">編輯</a>
|
<a :href="'view.aspx?orderId='+item.guaDanOrderNo" class="btn btn-primary">查看</a>
|
||||||
<a class="btn btn-outline-danger" @click="deleteGuadanOrder(item)">取消</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>
|
||||||
<template #item.room="{item}">
|
<template #item.room="{item}">
|
||||||
{{item.room.name}}
|
{{item.room.name}}
|
||||||
@@ -23,19 +52,60 @@
|
|||||||
<template #item.bed="{item}">
|
<template #item.bed="{item}">
|
||||||
{{item.bed.name}}
|
{{item.bed.name}}
|
||||||
</template>
|
</template>
|
||||||
<template #item.status="{item}">
|
<template #item.guadan_status="{item}">
|
||||||
{{item.status}}
|
{{item.guadan_status?.name}}
|
||||||
</template>
|
</template>
|
||||||
<template #item.start_date="{item}">
|
<template #item.start_date="{item}">
|
||||||
{{item.start_date | timeString('YYYY/MM/DD HH:mm')}}
|
{{item.start_date | timeString('YYYY/MM/DD')}}
|
||||||
</template>
|
</template>
|
||||||
<template #item.end_date="{item}">
|
<template #item.end_date="{item}">
|
||||||
{{item.end_date | timeString('YYYY/MM/DD HH:mm')}}
|
{{item.end_date | timeString('YYYY/MM/DD')}}
|
||||||
</template>
|
</template>
|
||||||
<template #item.created_at="{item}">
|
<template #item.created_at="{item}">
|
||||||
{{item.created_at | timeString('YYYY/MM/DD HH:mm')}}
|
{{item.created_at | timeString('YYYY/MM/DD HH:mm')}}
|
||||||
</template>
|
</template>
|
||||||
|
<template #item.activity="{item}">
|
||||||
|
{{item.activity?.subject}}
|
||||||
|
</template>
|
||||||
|
<template #item.is_timeout="{item}">
|
||||||
|
{{item.is_timeout ? '已超時': '否'}}
|
||||||
|
</template>
|
||||||
</v-data-table>
|
</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>
|
</div>
|
||||||
<!-- 更新修改確認彈出視窗 -->
|
<!-- 更新修改確認彈出視窗 -->
|
||||||
<message-modal ref="messageModal"></message-modal>
|
<message-modal ref="messageModal"></message-modal>
|
||||||
@@ -56,32 +126,100 @@
|
|||||||
return {
|
return {
|
||||||
items: [],
|
items: [],
|
||||||
headers: [
|
headers: [
|
||||||
{ text: '登记挂单莲友', value: 'bookerName'},
|
{ text: '登記掛單蓮友', value: 'bookerName' },
|
||||||
|
{ text: '掛單單號', value: 'guaDanOrderNo'},
|
||||||
{ text: '起始日期', value: 'start_date', align: 'center' },
|
{ text: '起始日期', value: 'start_date', align: 'center' },
|
||||||
{ text: '結束日期', value: 'end_date', align: 'center' },
|
{ text: '結束日期', value: 'end_date', align: 'center' },
|
||||||
{ text: '掛單人數', value: 'guest_count' },
|
{ text: '掛單人數', value: 'guest_count' },
|
||||||
{ text: '狀態', value: 'statusName', align: 'center' },
|
{ text: '狀態', value: 'guadan_status', align: 'center' },
|
||||||
{ text: '建立時間', value: 'created_at', align: 'center' },
|
{ text: '建立時間', value: 'created_at', align: 'center' },
|
||||||
{ text: '備註', value: 'notes', align: 'center' },
|
{ text: '關聯活動', value: 'activity', align: 'center' },
|
||||||
|
{ text: '超時退房', value: 'is_timeout', align: 'center' },
|
||||||
{ text: '操作', value: 'actions', align: 'center' }
|
{ text: '操作', value: 'actions', align: 'center' }
|
||||||
],
|
],
|
||||||
|
options: {
|
||||||
|
page: 1, // 當前頁
|
||||||
|
itemsPerPage: 10, // 每頁條數
|
||||||
|
sortBy: [],
|
||||||
|
sortDesc: []
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
startDate: null,
|
||||||
|
endDate: null,
|
||||||
|
guadanUser: null,
|
||||||
|
guaDanOrderNo: null,
|
||||||
|
},
|
||||||
|
total: 0,
|
||||||
|
loading: false,
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
resetTableOptions() {
|
||||||
|
this.options = {
|
||||||
|
page: 1,
|
||||||
|
itemsPerPage: 10,
|
||||||
|
sortBy: [],
|
||||||
|
sortDesc: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleSearch() {
|
||||||
|
|
||||||
|
let orderNo = this.search.guaDanOrderNo;
|
||||||
|
if (orderNo) {
|
||||||
|
orderNo = orderNo.replace(/\s+/g, '');
|
||||||
|
this.search.guaDanOrderNo = orderNo;
|
||||||
|
}
|
||||||
|
const val = this.search.guadanUser;
|
||||||
|
|
||||||
|
// 驗證是否包含空格
|
||||||
|
if (val && /\s/.test(val)) {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
message: '掛單登記人不能包含空格'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 驗證長度
|
||||||
|
if (val && val.length > 10) {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
message: '掛單登記人不能超過 10 個字'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.resetTableOptions();
|
||||||
|
},
|
||||||
|
clearSearch() {
|
||||||
|
this.search.startDate = null;
|
||||||
|
this.search.endDate = null;
|
||||||
|
this.search.guadanUser = null;
|
||||||
|
this.search.guaDanOrderNo = null;
|
||||||
|
this.resetTableOptions();
|
||||||
|
},
|
||||||
getGuadanOrder() {
|
getGuadanOrder() {
|
||||||
axios.get('/api/guadan/list')
|
if (this.loading) return;
|
||||||
|
axios.post('/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
|
||||||
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.items = res.data;
|
this.items = res.data.data;
|
||||||
|
this.total = res.data.total;
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
})
|
}).finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
deleteGuadanOrder(order) {
|
deleteGuadanOrder(order) {
|
||||||
this.$refs.confirmModal.open({
|
this.$refs.confirmModal.open({
|
||||||
message: '確認取消掛單?',
|
message: '確認取消掛單?',
|
||||||
onConfirm: () => {
|
onConfirm: () => {
|
||||||
axios.post('/api/guadan/delete', null, {
|
axios.post('/api/guadan/cancel', null, {
|
||||||
params: {
|
params: {
|
||||||
uuid: order.uuid
|
uuid: order.uuid
|
||||||
}
|
}
|
||||||
@@ -92,7 +230,7 @@
|
|||||||
})
|
})
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
this.$refs.messageModal.open({
|
this.$refs.messageModal.open({
|
||||||
message: '取消失敗'
|
message: error.response?.data || '取消失敗'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -101,12 +239,27 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
options: {
|
||||||
|
handler() {
|
||||||
|
this.getGuadanOrder(); // 監聽分頁、排序變化,自動載入數據
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getGuadanOrder();
|
this.getGuadanOrder();
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
pageCount() {
|
||||||
|
return Math.ceil(this.total / this.options.itemsPerPage)
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</asp:Content>
|
<style>
|
||||||
|
.row-timeout {
|
||||||
|
background-color: #ffdddd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</asp:Content>
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="statistics.aspx.cs" Inherits="admin_guadan_statistics" %>
|
|
||||||
|
|
||||||
<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 my-4">
|
|
||||||
<!-- 客房统计 -->
|
|
||||||
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-5 g-3">
|
|
||||||
<div class="col">
|
|
||||||
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
|
||||||
<div class="fs-2">🏠</div>
|
|
||||||
<div class="text-muted small mt-1">总房间数量</div>
|
|
||||||
<div class="fw-bold fs-5 mt-1">{{ roomStatistics.roomCount }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
|
||||||
<div class="fs-2">🚪</div>
|
|
||||||
<div class="text-muted small mt-1">空房间数量</div>
|
|
||||||
<div class="fw-bold fs-5 mt-1">{{ roomStatistics.emptyRoomCount }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
|
||||||
<div class="fs-2">🛏️</div>
|
|
||||||
<div class="text-muted small mt-1">总床位数量</div>
|
|
||||||
<div class="fw-bold fs-5 mt-1">
|
|
||||||
{{ roomStatistics.bedCount }} (男:{{ roomStatistics.maleBedCount }},女:{{ roomStatistics.femaleBedCount }})
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
|
||||||
<div class="fs-2">🛌</div>
|
|
||||||
<div class="text-muted small mt-1">可用空床</div>
|
|
||||||
<div class="fw-bold fs-5 mt-1">
|
|
||||||
{{ roomStatistics.emptyBedCount }} (男:{{ roomStatistics.emptyMaleBedCount }},女:{{ roomStatistics.emptyFemaleBedCount }})
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 挂单统计 -->
|
|
||||||
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-5 g-3 mt-1">
|
|
||||||
<div class="col">
|
|
||||||
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
|
||||||
<div class="fs-2">📝</div>
|
|
||||||
<div class="text-muted small mt-1">总挂单次数</div>
|
|
||||||
<div class="fw-bold fs-5 mt-1">{{ guadanStatistics.guadanTotalCount }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
|
||||||
<div class="fs-2">📋</div>
|
|
||||||
<div class="text-muted small mt-1">当前挂单数量</div>
|
|
||||||
<div class="fw-bold fs-5 mt-1">{{ guadanStatistics.guadanCurrentCount }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
|
||||||
<div class="fs-2">👥</div>
|
|
||||||
<div class="text-muted small mt-1">总挂单人数</div>
|
|
||||||
<div class="fw-bold fs-5 mt-1">
|
|
||||||
{{ guadanStatistics.guadanPeopleTotal }} (男:{{ guadanStatistics.guadanPeopleMale }},女:{{ guadanStatistics.guadanPeopleFemale }})
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
|
||||||
<div class="fs-2">👨👩</div>
|
|
||||||
<div class="text-muted small mt-1">当前挂单人数</div>
|
|
||||||
<div class="fw-bold fs-5 mt-1">
|
|
||||||
{{ guadanStatistics.guadanPeopleCurrent }} (男:{{ guadanStatistics.guadanPeopleCurrentMale }},女:{{ guadanStatistics.guadanPeopleCurrentFemale }})
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</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 {
|
|
||||||
roomStatistics: {
|
|
||||||
roomCount: 0,
|
|
||||||
emptyRoomCount: 0,
|
|
||||||
bedCount: 0,
|
|
||||||
maleBedCount: 0,
|
|
||||||
femaleBedCount: 0,
|
|
||||||
emptyBedCount: 0,
|
|
||||||
emptyMaleBedCount: 0,
|
|
||||||
emptyFemaleBedCount: 0
|
|
||||||
},
|
|
||||||
guadanStatistics: {
|
|
||||||
guadanTotalCount: 0,
|
|
||||||
guadanCurrentCount: 0,
|
|
||||||
guadanPeopleTotal: 0,
|
|
||||||
guadanPeopleMale: 0,
|
|
||||||
guadanPeopleFemale: 0,
|
|
||||||
guadanPeopleCurrent: 0,
|
|
||||||
guadanPeopleCurrentMale: 0,
|
|
||||||
guadanPeopleCurrentFemale: 0
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
GetGuadanStatistics() {
|
|
||||||
axios.get('/api/guadanStatistics/GetGuadanStatistics')
|
|
||||||
.then((res) => {
|
|
||||||
this.roomStatistics = res.data.roomStatistics;
|
|
||||||
this.guadanStatistics = res.data.guadanStatistics;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.GetGuadanStatistics();
|
|
||||||
|
|
||||||
// 每两分钟更新一次 (2 * 60 * 1000 毫秒)
|
|
||||||
setInterval(() => {
|
|
||||||
this.GetGuadanStatistics();
|
|
||||||
}, 1 * 60 * 1000);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</asp:Content>
|
|
||||||
|
|
||||||
348
web/admin/guadan/statistics_table.aspx
Normal file
348
web/admin/guadan/statistics_table.aspx
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="statistics_table.aspx.cs" Inherits="admin_guadan_statistics_table" %>
|
||||||
|
|
||||||
|
<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="section mb-6">
|
||||||
|
<v-card outlined class="pa-1">
|
||||||
|
<v-card-title class="headline grey--text text--darken-2">
|
||||||
|
掛單統計
|
||||||
|
</v-card-title>
|
||||||
|
<v-divider class="mb-4"></v-divider>
|
||||||
|
<v-card-text>
|
||||||
|
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-5 g-3 mt-1">
|
||||||
|
<div class="col">
|
||||||
|
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
||||||
|
<div class="fs-2">📝</div>
|
||||||
|
<div class="text-muted small mt-1">总挂单次数</div>
|
||||||
|
<div class="fw-bold fs-5 mt-1">{{ guadanStatistics.guadanTotalCount }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
||||||
|
<div class="fs-2">📋</div>
|
||||||
|
<div class="text-muted small mt-1">当前挂单数量</div>
|
||||||
|
<div class="fw-bold fs-5 mt-1">{{ guadanStatistics.guadanCurrentCount }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
||||||
|
<div class="fs-2">👥</div>
|
||||||
|
<div class="text-muted small mt-1">总挂单人数</div>
|
||||||
|
<div class="fw-bold fs-5 mt-1">
|
||||||
|
{{ guadanStatistics.guadanPeopleTotal }} (男:{{ guadanStatistics.guadanPeopleMale }},女:{{ guadanStatistics.guadanPeopleFemale }})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
|
||||||
|
<div class="fs-2">👨👩</div>
|
||||||
|
<div class="text-muted small mt-1">已預約掛單人數</div>
|
||||||
|
<div class="fw-bold fs-5 mt-1">
|
||||||
|
{{ guadanStatistics.guadanPeopleCurrent }} (男:{{ guadanStatistics.guadanPeopleCurrentMale }},女:{{ guadanStatistics.guadanPeopleCurrentFemale }})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 近期床位使用統計 -->
|
||||||
|
<div class="section container">
|
||||||
|
<!-- 日期筛选区 -->
|
||||||
|
<div class="d-flex align-center flex-wrap" style="gap: 5px;">
|
||||||
|
<!-- 开始日期 -->
|
||||||
|
<v-menu
|
||||||
|
ref="menu1"
|
||||||
|
v-model="menu1"
|
||||||
|
:close-on-content-click="false"
|
||||||
|
transition="scale-transition"
|
||||||
|
offset-y
|
||||||
|
min-width="auto"
|
||||||
|
>
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-text-field
|
||||||
|
v-model="startDate"
|
||||||
|
label="開始日期"
|
||||||
|
prepend-icon="mdi-calendar"
|
||||||
|
readonly
|
||||||
|
v-bind="attrs"
|
||||||
|
v-on="on"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
></v-text-field>
|
||||||
|
</template>
|
||||||
|
<v-date-picker v-model="startDate" @input="menu1 = false"></v-date-picker>
|
||||||
|
</v-menu>
|
||||||
|
|
||||||
|
<!-- 结束日期 -->
|
||||||
|
<v-menu
|
||||||
|
ref="menu2"
|
||||||
|
v-model="menu2"
|
||||||
|
:close-on-content-click="false"
|
||||||
|
transition="scale-transition"
|
||||||
|
offset-y
|
||||||
|
min-width="auto"
|
||||||
|
>
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-text-field
|
||||||
|
v-model="endDate"
|
||||||
|
label="結束日期"
|
||||||
|
prepend-icon="mdi-calendar"
|
||||||
|
readonly
|
||||||
|
v-bind="attrs"
|
||||||
|
v-on="on"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
></v-text-field>
|
||||||
|
</template>
|
||||||
|
<v-date-picker v-model="endDate" @input="menu2 = false"></v-date-picker>
|
||||||
|
</v-menu>
|
||||||
|
|
||||||
|
<!-- 查询按钮 -->
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
@click="getList"
|
||||||
|
style="align-self: stretch;"
|
||||||
|
>
|
||||||
|
查詢
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
style="align-self: stretch;"
|
||||||
|
@click="exportStatisticsToExcel">
|
||||||
|
導出下面表格數據到Excel
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-divider class="mb-4"></v-divider>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<v-data-table
|
||||||
|
:items="items"
|
||||||
|
:headers="headers"
|
||||||
|
class="elevation-2"
|
||||||
|
dense
|
||||||
|
hide-default-footer
|
||||||
|
:items-per-page="10"
|
||||||
|
>
|
||||||
|
<template #item.date="{ item }">
|
||||||
|
<span>{{ item.date | timeString('YYYY-MM-DD') }}</span>
|
||||||
|
</template>
|
||||||
|
<template #item.todaytotalbookers="{item}">
|
||||||
|
<span>
|
||||||
|
{{item?.todaytotalbookers + '(男: ' + item.bookmale + ', 女:' + item.bookfemale + ')'}}
|
||||||
|
</span>
|
||||||
|
<button type="button" class="btn btn-outline-primary" @click="showBookDialog(item, '已預約','booking')">查看預約人</button>
|
||||||
|
</template>
|
||||||
|
<template #item.checkin="{item}">
|
||||||
|
<span>
|
||||||
|
{{item?.checkin + '(男: ' + item.checkinmale + ', 女:' + item.checkinfemale + ')'}}
|
||||||
|
</span>
|
||||||
|
<button type="button" class="btn btn-outline-primary" @click="showBookDialog(item, '已入住', 'checkin')">查看入住人</button>
|
||||||
|
</template>
|
||||||
|
<template #item.bedusagerate="{ item }">
|
||||||
|
{{ ((item.todaytotalbookers / bedcount) * 100).toFixed(2) + '%' }}
|
||||||
|
</template>
|
||||||
|
<template #item.roomcount="{item}">
|
||||||
|
{{roomcount}}
|
||||||
|
</template>
|
||||||
|
<template #item.bedcount="{item}">
|
||||||
|
{{bedcount}}
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<v-dialog v-model="bookerDialog.show" max-width="500">
|
||||||
|
<v-card
|
||||||
|
style="width: 40vw; height: 50vh; display: flex; flex-direction: column;"
|
||||||
|
>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<v-card-title class="text-h5" style="flex: 0 0 auto; background-color: #1976D2; color: white; padding: 16px;">
|
||||||
|
{{ bookerDialog.title }}
|
||||||
|
</v-card-title>
|
||||||
|
|
||||||
|
<!-- 内容撑满 -->
|
||||||
|
<v-card-text
|
||||||
|
style="flex: 1; overflow-y: auto;"
|
||||||
|
>
|
||||||
|
<v-data-table
|
||||||
|
:items="bookerDialog.items"
|
||||||
|
:headers="bookerDialog.headers">
|
||||||
|
|
||||||
|
</v-data-table>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<!-- 底部按钮 -->
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn text @click="closeBookDialog">關閉</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.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 {
|
||||||
|
items: [],
|
||||||
|
headers: [
|
||||||
|
{ text: '日期', value: 'date' },
|
||||||
|
{ text: '房间数量', value: 'roomcount' },
|
||||||
|
{ text: '床位数量', value: 'bedcount' },
|
||||||
|
{ text: '预约人数', value: 'todaytotalbookers' },
|
||||||
|
{ text: '已入住人数', value: 'checkin'},
|
||||||
|
{ text: '可用床位', value: 'availableBeds' },
|
||||||
|
{ text: '床位利用率', value: 'bedusagerate' }
|
||||||
|
],
|
||||||
|
startDate: null,
|
||||||
|
endDate: null,
|
||||||
|
menu1: false,
|
||||||
|
menu2: false,
|
||||||
|
bedcount: 0,
|
||||||
|
roomcount: 0,
|
||||||
|
guadanStatistics: {
|
||||||
|
guadanTotalCount: 0,
|
||||||
|
guadanCurrentCount: 0,
|
||||||
|
guadanPeopleTotal: 0,
|
||||||
|
guadanPeopleMale: 0,
|
||||||
|
guadanPeopleFemale: 0,
|
||||||
|
guadanPeopleCurrent: 0,
|
||||||
|
guadanPeopleCurrentMale: 0,
|
||||||
|
guadanPeopleCurrentFemale: 0
|
||||||
|
},
|
||||||
|
bookerDialog: {
|
||||||
|
title: "",
|
||||||
|
show: false,
|
||||||
|
items: [],
|
||||||
|
headers: [
|
||||||
|
{ text: '姓名', value: 'name' },
|
||||||
|
{ text: "性别", value: 'gender'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showBookDialog(item, title, type = null) {
|
||||||
|
this.bookerDialog.title = title;
|
||||||
|
this.bookerDialog.show = true;
|
||||||
|
if (type === 'booking') {
|
||||||
|
this.getBookerDialogBookingItems(item.date);
|
||||||
|
}
|
||||||
|
else if (type === 'checkin') {
|
||||||
|
this.getBookerDialogCheckInItems(item.date);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeBookDialog() {
|
||||||
|
this.bookerDialog.show = false;
|
||||||
|
this.bookerDialog.title = "";
|
||||||
|
this.bookerDialog.items = [];
|
||||||
|
},
|
||||||
|
async getBookerDialogBookingItems(date) {
|
||||||
|
try {
|
||||||
|
const res = await axios.get(HTTP_HOST + 'api/guadan/guest/booking/list', {
|
||||||
|
params: {
|
||||||
|
date: date
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.bookerDialog.items = res.data;
|
||||||
|
} catch(error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getBookerDialogCheckInItems(date) {
|
||||||
|
try {
|
||||||
|
const res = await axios.get(HTTP_HOST + 'api/guadan/guest/checkin/list', {
|
||||||
|
params: {
|
||||||
|
date: date
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.bookerDialog.items = res.data;
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getList() {
|
||||||
|
try {
|
||||||
|
const res = await axios.get(HTTP_HOST + 'api/guadan/guadanstatisticstable/list', {
|
||||||
|
params: {
|
||||||
|
start: this.startDate || '',
|
||||||
|
end: this.endDate || ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.items = res.data.statistics;
|
||||||
|
this.roomcount = res.data.roomcount;
|
||||||
|
this.bedcount = res.data.bedcount;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exportStatisticsToExcel() {
|
||||||
|
if (!this.items || !this.items.length) {
|
||||||
|
console.warn("没有数据可导出");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 取 items 数组并格式化
|
||||||
|
const sheetData = this.items.map(item => ({
|
||||||
|
日期: item.date.split('T')[0], // 格式化成 YYYY-MM-DD
|
||||||
|
预订人数: item.todaytotalbookers,
|
||||||
|
入住人数: item.checkin
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 2. 转换成 XLSX Sheet
|
||||||
|
const ws = XLSX.utils.json_to_sheet(sheetData);
|
||||||
|
|
||||||
|
// 3. 创建 Workbook 并添加 Sheet
|
||||||
|
const wb = XLSX.utils.book_new();
|
||||||
|
XLSX.utils.book_append_sheet(wb, ws, "统计数据");
|
||||||
|
|
||||||
|
// 4. 写入 Excel 并下载
|
||||||
|
const wbout = XLSX.write(wb, { bookType: "xlsx", type: "array" });
|
||||||
|
saveAs(new Blob([wbout], { type: "application/octet-stream" }), "statistics.xlsx");
|
||||||
|
},
|
||||||
|
GetGuadanStatistics() {
|
||||||
|
axios.get('/api/guadanStatistics/GetGuadanStatistics')
|
||||||
|
.then((res) => {
|
||||||
|
this.guadanStatistics = res.data.guadanStatistics;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getList();
|
||||||
|
this.GetGuadanStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<!-- CDN 方式引入 XLSX 和 FileSaver -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
|
||||||
|
|
||||||
|
</asp:Content>
|
||||||
|
|
||||||
14
web/admin/guadan/statistics_table.aspx.cs
Normal file
14
web/admin/guadan/statistics_table.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_statistics_table : MyWeb.config
|
||||||
|
{
|
||||||
|
protected void Page_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
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('/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('/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('/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>
|
||||||
@@ -5,7 +5,7 @@ using System.Web;
|
|||||||
using System.Web.UI;
|
using System.Web.UI;
|
||||||
using System.Web.UI.WebControls;
|
using System.Web.UI.WebControls;
|
||||||
|
|
||||||
public partial class admin_guadan_statistics : MyWeb.config
|
public partial class admin_guadan_view : MyWeb.config
|
||||||
{
|
{
|
||||||
protected void Page_Load(object sender, EventArgs e)
|
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)
|
||||||
|
{
|
||||||
|
// 頁面初始化(暫無邏輯)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,53 +19,24 @@ public partial class admin_printpw_index : MyWeb.function
|
|||||||
private string previousOrderno = "";
|
private string previousOrderno = "";
|
||||||
protected void Page_Load(object sender, EventArgs e)
|
protected void Page_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
//Response.Write("item:"+Request["item"]+"<br>");
|
|
||||||
//Response.Write("file:"+Request["file"]+"<br>");
|
|
||||||
//Response.Write("list:"+Request["list"]+"<br>");
|
|
||||||
//if (!IsPostBack)
|
|
||||||
//{
|
|
||||||
this.Title = "預覽牌位";
|
this.Title = "預覽牌位";
|
||||||
if (Request.HttpMethod == "POST")
|
if (Request.HttpMethod == "POST")
|
||||||
{
|
{
|
||||||
/*if (!String.IsNullOrEmpty(Request["item"]) &&
|
|
||||||
!String.IsNullOrEmpty(Request["file"]) &&
|
|
||||||
!String.IsNullOrEmpty(Request["list"])
|
|
||||||
)*/
|
|
||||||
if (!String.IsNullOrEmpty(Request["order_no"]))
|
if (!String.IsNullOrEmpty(Request["order_no"]))
|
||||||
{
|
{
|
||||||
var order_no = Request["order_no"];
|
var order_no = Request["order_no"];
|
||||||
var oderList = _db.pro_order_detail
|
var oderList = _db.pro_order_detail
|
||||||
.Where(u => u.order_no == order_no && u.printed_files != null)
|
.Where(u => u.order_no == order_no)
|
||||||
|
.Where(u => (u.parent_num != null)
|
||||||
|
|| u.actItem.subject.Contains("牌")
|
||||||
|
|| !string.IsNullOrEmpty(u.f_num_tablet))
|
||||||
|
//因為目前在[pro_order_detail]表中,沒有辦法區分那些項目是牌位,
|
||||||
|
//只有根據某些欄位來做部分篩選,可能會篩選錯
|
||||||
|
//但是為什麼沒有欄位可以區分一個項目是不是牌位呢?
|
||||||
.Select(u => new { detail_num = u.num, actItem_num = u.actItem_num }).ToArray();
|
.Select(u => new { detail_num = u.num, actItem_num = u.actItem_num }).ToArray();
|
||||||
Repeater1.DataSource = oderList;
|
Repeater1.DataSource = oderList;
|
||||||
Repeater1.DataBind();
|
Repeater1.DataBind();
|
||||||
}
|
}
|
||||||
else if (!String.IsNullOrEmpty(Request["activity_num"]))
|
|
||||||
{
|
|
||||||
//var _details = Newtonsoft.Json.JsonConvert.DeserializeObject<int[]>(Request["list"]);
|
|
||||||
//string json = "";
|
|
||||||
//using (System.IO.StreamReader oSR = new System.IO.StreamReader(Request.InputStream))
|
|
||||||
// json = oSR.ReadToEnd();
|
|
||||||
int activity_num = Convert.ToInt32(Request["activity_num"]);
|
|
||||||
//Repeater1.DataSource = _details;
|
|
||||||
var orderList = _db.pro_order.Where(u => u.activity_num == activity_num).Select(u => u.order_no).ToList();
|
|
||||||
var gdzOrderList = _db.pro_order_detail.Where(u => orderList.Contains(u.order_no) && u.print_id.Contains("主") ).Select(u=>u.order_no).Distinct().ToArray();
|
|
||||||
var datalist = _db.pro_order_detail
|
|
||||||
.Where(u => gdzOrderList.Contains(u.order_no) && u.print_id.Contains("主") && u.parent_num != null && u.printed_files != null)
|
|
||||||
.OrderBy(o => o.order_no)
|
|
||||||
.ThenBy(o => o.actItem_num)
|
|
||||||
.ThenBy(o=>o.print_id)
|
|
||||||
.Select(u => new {detail_num=u.num ,actItem_num=u.actItem_num})
|
|
||||||
.ToArray();
|
|
||||||
//List<int> ints = new List<int>();
|
|
||||||
//ints.Add(12133);
|
|
||||||
Repeater1.DataSource = datalist;
|
|
||||||
Repeater1.DataBind();
|
|
||||||
if (!String.IsNullOrEmpty(Request["title"]))
|
|
||||||
{
|
|
||||||
this.Title += " - " + Request["title"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Response.Clear();
|
Response.Clear();
|
||||||
@@ -74,9 +45,6 @@ public partial class admin_printpw_index : MyWeb.function
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
|
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
|
||||||
@@ -248,8 +216,8 @@ public partial class admin_printpw_index : MyWeb.function
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var msg = ex.Message;
|
var msg = ex.Message;
|
||||||
ret[0] = "??:" + msg;
|
ret[0] = "";
|
||||||
ret[1] = "??";
|
ret[1] = "";
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
@page a4l {
|
@page a4l {
|
||||||
size: a4 landscape;
|
size: a4 landscape;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
margin-top:6mm;
|
||||||
|
margin-left:6mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@page a5 {
|
@page a5 {
|
||||||
@@ -133,6 +135,22 @@ pre {
|
|||||||
line-height: calc(var(--fs_w) * 1.0);
|
line-height: calc(var(--fs_w) * 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-block.fit-text.add-space {
|
||||||
|
letter-spacing: 0.5em;
|
||||||
|
}
|
||||||
|
.text-block.fit-text.mid_text.add-space {
|
||||||
|
padding-top: 0.5em;
|
||||||
|
}
|
||||||
|
.text-block.fit-text.mid_text.add-space.add-space-3 {
|
||||||
|
letter-spacing: 1.5em;
|
||||||
|
padding-top: 1.5em;
|
||||||
|
}
|
||||||
|
body.tblt-m .left_text {
|
||||||
|
--font-max: 30pt;
|
||||||
|
}
|
||||||
|
body.tblt-m .top_text_2 {
|
||||||
|
right: 8mm;
|
||||||
|
}
|
||||||
.vertical {
|
.vertical {
|
||||||
writing-mode: vertical-rl;
|
writing-mode: vertical-rl;
|
||||||
/*text-orientation: upright;*/
|
/*text-orientation: upright;*/
|
||||||
@@ -367,6 +385,10 @@ pre {
|
|||||||
left: 2mm;
|
left: 2mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.top_text_3 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/*舊式紙張*/
|
/*舊式紙張*/
|
||||||
body.tablet-l {
|
body.tablet-l {
|
||||||
--page-w: 274mm;
|
--page-w: 274mm;
|
||||||
@@ -548,6 +570,9 @@ body.tblt-l.a3.l2b .mid_text {
|
|||||||
--divh: 60mm;
|
--divh: 60mm;
|
||||||
top: 40%;
|
top: 40%;
|
||||||
}
|
}
|
||||||
|
body.tblt-l.a3 .left_text {
|
||||||
|
--font-max: 36pt;
|
||||||
|
}
|
||||||
|
|
||||||
body.tblt-l.a3.l2b .mid_text_2 {
|
body.tblt-l.a3.l2b .mid_text_2 {
|
||||||
--divh: 180mm;
|
--divh: 180mm;
|
||||||
@@ -638,7 +663,8 @@ body.tblt-m.a4-mrg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.tblt-m.a4-mrg .page {
|
body.tblt-m.a4-mrg .page {
|
||||||
--page-w: 100mm;
|
--page-w: 95mm;
|
||||||
|
margin-left:5mm;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,9 +789,8 @@ body.tblt-xs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.tblt-xs.a3-mrg .page {
|
body.tblt-xs.a3-mrg .page {
|
||||||
/*--page-w: 57mm;*/
|
--page-w: 57mm;
|
||||||
--page-w: 59mm;
|
--page-h: 98mm;
|
||||||
--page-h: 100mm;
|
|
||||||
page-break-after: auto;
|
page-break-after: auto;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
@@ -775,13 +800,11 @@ body.tblt-xs.a4l-mrg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.tblt-xs.a4l-mrg .page {
|
body.tblt-xs.a4l-mrg .page {
|
||||||
/* --page-w: 57mm; */
|
--page-w: 57mm;
|
||||||
--page-w: 59mm;
|
--page-h: 98mm;
|
||||||
--page-h: 100mm;
|
|
||||||
page-break-after: auto;
|
page-break-after: auto;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.tblt-xs .top_text_1 {
|
body.tblt-xs .top_text_1 {
|
||||||
font-size: 8pt;
|
font-size: 8pt;
|
||||||
}
|
}
|
||||||
@@ -800,9 +823,9 @@ body.tblt-xs .mid_text_2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.tblt-xs .right_text {
|
body.tblt-xs .right_text {
|
||||||
--divw: 12mm;
|
--divw: 10mm;
|
||||||
--divh: 60mm;
|
--divh: 60mm;
|
||||||
right: 0mm;
|
right: 2mm;
|
||||||
top: 25mm;
|
top: 25mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -825,8 +848,7 @@ body.tblt-xs .top_text_2{
|
|||||||
/*[標準X2B]隨喜牌位-佛力超薦-往生蓮位-A3(直)*/
|
/*[標準X2B]隨喜牌位-佛力超薦-往生蓮位-A3(直)*/
|
||||||
right: 2mm;
|
right: 2mm;
|
||||||
right: 3.0mm;
|
right: 3.0mm;
|
||||||
right: 3.5mm;
|
right: 5mm;
|
||||||
/* right: 4.0mm; */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body.tblt-xs .txt_up {
|
body.tblt-xs .txt_up {
|
||||||
@@ -1075,35 +1097,4 @@ body.prayer-h pre {
|
|||||||
/*[標準X1A]隨喜牌位-佛光注照-長生祿位-A4(橫) */
|
/*[標準X1A]隨喜牌位-佛光注照-長生祿位-A4(橫) */
|
||||||
* {
|
* {
|
||||||
outline:0 none !important;
|
outline:0 none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*让自定义的分页生效,在某个div后面产生class-page从而分页,当牌位不是同一家人的时候就分页*/
|
|
||||||
@media print {
|
|
||||||
.page-break {
|
|
||||||
display: block !important;
|
|
||||||
width: 100%;
|
|
||||||
height: 1px;
|
|
||||||
visibility: hidden;
|
|
||||||
page-break-after: always;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page {
|
|
||||||
page-break-inside: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@page {
|
|
||||||
orphans: 1;
|
|
||||||
widows: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d-flex {
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-break::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
height: 1px;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,17 +32,25 @@ function init_print() {
|
|||||||
//console.log(i, $(this).html(),$(this).text());
|
//console.log(i, $(this).html(),$(this).text());
|
||||||
//console.log(i, txt==htm);
|
//console.log(i, txt==htm);
|
||||||
//console.log(i, txt_arr, line, line_len);
|
//console.log(i, txt_arr, line, line_len);
|
||||||
line_len = Math.ceil(line_len / 5) * 5;
|
line_len = Math.ceil(line_len / 3) * 3;
|
||||||
//if(line>1){
|
//if(line>1){
|
||||||
css = $(this).attr("style")||"";
|
css = $(this).attr("style")||"";
|
||||||
if(css.length>0){
|
if(css.length>0){
|
||||||
css += ";";
|
css += ";";
|
||||||
}
|
}
|
||||||
css += "--lines:" + line + ";--line_len:" + line_len + ";";
|
css += "--lines:" + line + ";--line_len:" + line_len + ";";
|
||||||
//debugger;
|
|
||||||
|
//字少時, 加空間
|
||||||
|
let allShort = txt_arr2.every(line => line.trim().length <= 7);
|
||||||
|
let addSpaceClass = allShort ? "add-space" : "";
|
||||||
|
allShort = txt_arr2.every(line => line.trim().length <= 3);
|
||||||
|
addSpaceClass += allShort ? " add-space-3" : "";
|
||||||
|
|
||||||
htm_lines = txt_arr2.join("<br>");
|
htm_lines = txt_arr2.join("<br>");
|
||||||
$(this).attr("style", css);
|
$(this)
|
||||||
$(this).html(htm_lines);
|
.attr("style", css)
|
||||||
|
.addClass(addSpaceClass)
|
||||||
|
.html(htm_lines);
|
||||||
//}
|
//}
|
||||||
//console.log(i, line, line_len, css,txt);
|
//console.log(i, line, line_len, css,txt);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -153,6 +153,9 @@
|
|||||||
<template #item.slot_type ="{item}">
|
<template #item.slot_type ="{item}">
|
||||||
{{item.detail.actItem?.substring(0,3)}}
|
{{item.detail.actItem?.substring(0,3)}}
|
||||||
</template>
|
</template>
|
||||||
|
<template #item.up_time ="{item}">
|
||||||
|
{{item.up_time|timeString('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
<template #item.print="{item}">
|
<template #item.print="{item}">
|
||||||
<v-icon color="blue" class="mr-2" @click="yulan_single(item);" >
|
<v-icon color="blue" class="mr-2" @click="yulan_single(item);" >
|
||||||
mdi-printer
|
mdi-printer
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<asp:Literal ID="L_msg" runat="server" />
|
<asp:Literal ID="L_msg" runat="server" />
|
||||||
<asp:HiddenField ID="HF_Id" runat="server" />
|
<asp:HiddenField ID="HF_Code" runat="server" />
|
||||||
|
|
||||||
<div class="form-group mb-3">
|
<div class="form-group mb-3">
|
||||||
<label for="TB_Name">名稱</label>
|
<label for="TB_Name">名稱</label>
|
||||||
|
|||||||
@@ -1,35 +1,36 @@
|
|||||||
using Model;
|
using Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web;
|
|
||||||
using System.Web.UI;
|
using System.Web.UI;
|
||||||
using System.Web.UI.WebControls;
|
using System.Web.UI.WebControls;
|
||||||
|
|
||||||
public partial class admin_region_bed_bedstatus_create : MyWeb.config
|
public partial class admin_region_bed_bedstatus_create : MyWeb.config
|
||||||
{
|
{
|
||||||
private Model.ezEntities _db = new Model.ezEntities();
|
private Model.ezEntities _db = new Model.ezEntities();
|
||||||
|
|
||||||
protected void Page_Load(object sender, EventArgs e)
|
protected void Page_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (!IsPostBack) // 加這行
|
if (!IsPostBack)
|
||||||
{
|
{
|
||||||
if (Guid.TryParse(Request.QueryString["statusid"], out Guid id))
|
var code = Request.QueryString["code"];
|
||||||
|
if (!string.IsNullOrEmpty(code))
|
||||||
{
|
{
|
||||||
LoadData(id);
|
LoadData(code);
|
||||||
L_title.Text = "編輯區域類型";
|
L_title.Text = "編輯區域類型";
|
||||||
}
|
}
|
||||||
|
|
||||||
var categoryList = RegionRoomBedStatus.GetCategoryList();
|
var categoryList = RegionRoomBedStatus.GetCategoryList();
|
||||||
// 假设你的下拉控件ID叫 ddlCategory
|
|
||||||
TB_Category.DataSource = categoryList;
|
TB_Category.DataSource = categoryList;
|
||||||
TB_Category.DataTextField = "Text"; // 显示文字
|
TB_Category.DataTextField = "Text"; // 顯示文字
|
||||||
TB_Category.DataValueField = "Value"; // 选项值
|
TB_Category.DataValueField = "Value"; // 選項值
|
||||||
TB_Category.DataBind();
|
TB_Category.DataBind();
|
||||||
TB_Category.Items.Insert(0, new ListItem("--请选择分类--", ""));
|
TB_Category.Items.Insert(0, new ListItem("--請選擇分類--", ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void LoadData(Guid id)
|
|
||||||
|
private void LoadData(string code)
|
||||||
{
|
{
|
||||||
var rt = _db.RegionRoomBedStatus.FirstOrDefault(r => r.Uuid == id);
|
var rt = _db.RegionRoomBedStatus.FirstOrDefault(r => r.Code == code);
|
||||||
if (rt == null)
|
if (rt == null)
|
||||||
{
|
{
|
||||||
L_msg.Text = "<div class='alert alert-danger'>找不到資料</div>";
|
L_msg.Text = "<div class='alert alert-danger'>找不到資料</div>";
|
||||||
@@ -37,22 +38,24 @@ public partial class admin_region_bed_bedstatus_create : MyWeb.config
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HF_Id.Value = rt.Uuid.ToString();
|
HF_Code.Value = rt.Code; // ✅ 以 Code 為唯一識別
|
||||||
TB_Name.Text = rt.Name;
|
TB_Name.Text = rt.Name;
|
||||||
TB_Code.Text = rt.Code;
|
TB_Code.Text = rt.Code;
|
||||||
TB_Category.SelectedValue = rt.Category?.ToString();
|
TB_Category.SelectedValue = rt.Category?.ToString();
|
||||||
Description.Text = rt.Description;
|
Description.Text = rt.Description;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void BTN_Save_Click(object sender, EventArgs e)
|
protected void BTN_Save_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RegionRoomBedStatus rt;
|
RegionRoomBedStatus rt;
|
||||||
if (Guid.TryParse(HF_Id.Value, out Guid id))
|
var code = HF_Code.Value; // ✅ 用隱藏欄位的 Code 判斷
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(code))
|
||||||
{
|
{
|
||||||
// 更新
|
// 更新
|
||||||
rt = _db.RegionRoomBedStatus.FirstOrDefault(r => r.Uuid == id);
|
rt = _db.RegionRoomBedStatus.FirstOrDefault(r => r.Code == code);
|
||||||
if (rt == null)
|
if (rt == null)
|
||||||
{
|
{
|
||||||
L_msg.Text = "<div class='alert alert-danger'>資料不存在</div>";
|
L_msg.Text = "<div class='alert alert-danger'>資料不存在</div>";
|
||||||
@@ -63,19 +66,20 @@ public partial class admin_region_bed_bedstatus_create : MyWeb.config
|
|||||||
{
|
{
|
||||||
// 新增
|
// 新增
|
||||||
rt = new RegionRoomBedStatus();
|
rt = new RegionRoomBedStatus();
|
||||||
rt.Uuid = Guid.NewGuid();
|
rt.Code = TB_Code.Text.Trim(); // ✅ 以 Code 當主鍵
|
||||||
_db.RegionRoomBedStatus.Add(rt);
|
_db.RegionRoomBedStatus.Add(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.Name = TB_Name.Text.Trim();
|
rt.Name = TB_Name.Text.Trim();
|
||||||
if (rt.Name.Length == 0)
|
if (string.IsNullOrEmpty(rt.Name))
|
||||||
{
|
{
|
||||||
L_msg.Text = "<div class='alert alert-danger'>名稱不能为空</div>";
|
L_msg.Text = "<div class='alert alert-danger'>名稱不能為空</div>";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rt.Code = TB_Code.Text.Trim();
|
|
||||||
rt.Description = Description.Text.Trim();
|
rt.Description = Description.Text.Trim();
|
||||||
if(int.TryParse(TB_Category.SelectedValue, out int category))
|
|
||||||
|
if (int.TryParse(TB_Category.SelectedValue, out int category))
|
||||||
{
|
{
|
||||||
rt.Category = category;
|
rt.Category = category;
|
||||||
}
|
}
|
||||||
@@ -83,16 +87,18 @@ public partial class admin_region_bed_bedstatus_create : MyWeb.config
|
|||||||
{
|
{
|
||||||
rt.Category = null;
|
rt.Category = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
|
|
||||||
L_msg.Text = "<div class='alert alert-success'>儲存成功</div>";
|
L_msg.Text = "<div class='alert alert-success'>儲存成功</div>";
|
||||||
|
|
||||||
// 如果是新增,更新隱藏欄位並切換標題為編輯
|
// ✅ 如果是新增,更新隱藏欄位並切換標題
|
||||||
if (HF_Id.Value == "")
|
if (string.IsNullOrEmpty(HF_Code.Value))
|
||||||
{
|
{
|
||||||
HF_Id.Value = rt.Uuid.ToString();
|
HF_Code.Value = rt.Code;
|
||||||
L_title.Text = "編輯區域類型";
|
L_title.Text = "編輯區域類型";
|
||||||
}
|
}
|
||||||
|
|
||||||
Response.Redirect("index.aspx");
|
Response.Redirect("index.aspx");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -100,4 +106,4 @@ public partial class admin_region_bed_bedstatus_create : MyWeb.config
|
|||||||
L_msg.Text = $"<div class='alert alert-danger'>錯誤:{ex.Message}</div>";
|
L_msg.Text = $"<div class='alert alert-danger'>錯誤:{ex.Message}</div>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
>
|
>
|
||||||
<template #item.actions="{item}">
|
<template #item.actions="{item}">
|
||||||
<a :href="'create.aspx?statusid='+item.uuid" class="btn btn-primary"><i class="mdi mdi-pencil"></i>修改</a>
|
<a :href="'create.aspx?code='+item.code" class="btn btn-primary"><i class="mdi mdi-pencil"></i>修改</a>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-danger"
|
class="btn btn-outline-danger"
|
||||||
@@ -46,11 +46,10 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
headers: [
|
headers: [
|
||||||
{ text: 'Id', value: 'id' },
|
|
||||||
{ text: '狀態名稱', value: 'name' },
|
{ text: '狀態名稱', value: 'name' },
|
||||||
{ text: '狀態代碼', value: 'code' },
|
{ text: '狀態代碼', value: 'code' },
|
||||||
{ text: '描述', value: 'description' },
|
{ text: '描述', value: 'description' },
|
||||||
{ text: '状态分类', value: 'categoryName'},
|
{ text: '状态分类', value: 'categoryName' },
|
||||||
{ text: '', value: 'actions' }
|
{ text: '', value: 'actions' }
|
||||||
],
|
],
|
||||||
items: [],
|
items: [],
|
||||||
@@ -75,10 +74,10 @@
|
|||||||
},
|
},
|
||||||
deleteStatus(item) {
|
deleteStatus(item) {
|
||||||
axios.post('/api/region/bed/status/delete', null, {
|
axios.post('/api/region/bed/status/delete', null, {
|
||||||
params: { id: item.uuid }
|
params: { code: item.code }
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.items = this.items.filter(i => i.uuid != item.uuid);
|
this.items = this.items.filter(i => i.code != item.code);
|
||||||
this.$refs.messageModal.open({
|
this.$refs.messageModal.open({
|
||||||
title: '操作成功',
|
title: '操作成功',
|
||||||
message: '刪除成功!',
|
message: '刪除成功!',
|
||||||
|
|||||||
@@ -108,11 +108,12 @@
|
|||||||
|
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||||
<div v-for="region in regions" :key="region.uuid" class="region-block mb-4">
|
<div v-for="region in regions" :key="region.uuid" class="region-block mb-4"
|
||||||
<h2 class="region-title mb-3">{{ region.regionPath }}</h2>
|
:style="region.isStop ? { pointerEvents: 'none', opacity: '0.6', backgroundColor: '#f8d7da' } : {}">
|
||||||
|
<h2 class="region-title mb-3">{{region.isStop?(region.regionPath + '(已停用)'): region.regionPath }}</h2>
|
||||||
|
|
||||||
<div class="row g-3 justify-content-start">
|
<div class="row g-3 justify-content-start">
|
||||||
<div v-for="room in region.room" :key="room.ruid" class="col-12 col-md-6 col-lg-4">
|
<div v-for="room in region.room" :key="room.ruid" class="col-12 col-md-6 col-lg-6">
|
||||||
|
|
||||||
<div class="card h-100 shadow-sm" style="min-height: 300px; max-height: 400px; overflow-y: auto; border-radius: 0.5rem;">
|
<div class="card h-100 shadow-sm" style="min-height: 300px; max-height: 400px; overflow-y: auto; border-radius: 0.5rem;">
|
||||||
<!-- 上部:房間名稱 -->
|
<!-- 上部:房間名稱 -->
|
||||||
@@ -138,20 +139,26 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">床位名稱</th>
|
<th scope="col">床位名稱</th>
|
||||||
<th scope="col">是否可用</th>
|
|
||||||
<th scope="col">使用明細</th>
|
<th scope="col">使用明細</th>
|
||||||
|
<th scope="col">掛單</th>
|
||||||
|
<th scope="col">當前狀態</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="bed in room.beds" :key="bed.uuid"
|
<tr v-for="bed in room.beds" :key="bed.uuid"
|
||||||
:class="bed.canuse ? 'table-success' : 'table-danger'">
|
:class="bed.canuse ? 'table-success' : 'table-danger'">
|
||||||
<td>{{ bed.name }}</td>
|
<td>{{ bed.name }}</td>
|
||||||
<td :class="!bed.canuse ? 'text-danger' : 'text-success'">
|
|
||||||
{{ bed.canuse ? '是' : '否' }}
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="btn btn-primary" @click="showBedSchedule(bed)">查看明細</button>
|
<button type="button" class="btn btn-primary" @click="showBedSchedule(bed)">查看明細</button>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-primary">
|
||||||
|
快速掛單
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{bed.statusname}}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -165,43 +172,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<v-dialog v-model="bedSchedule.dialogVisible" max-width="900">
|
<v-dialog v-model="bedSchedule.dialogVisible" max-width="900px">
|
||||||
<v-card>
|
<v-card
|
||||||
<v-card-title>
|
style="min-height:50vh; max-height:80vh; display:flex; flex-direction:column;"
|
||||||
<span class="text-h6">床位排程明細 - {{ bedSchedule.selectedBed?.name }}</span>
|
>
|
||||||
<v-spacer></v-spacer>
|
<v-card-title>
|
||||||
<v-btn icon @click="closeBedSchedule">
|
<span class="text-h6">床位排程明細 - {{ bedSchedule.selectedBed?.name }}</span>
|
||||||
<v-icon>mdi-close</v-icon>
|
<v-spacer></v-spacer>
|
||||||
</v-btn>
|
<v-btn icon @click="closeBedSchedule"><v-icon>mdi-close</v-icon></v-btn>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-text>
|
<!-- 关键改动:flex:1 1 auto; min-height:0; overflow-y:auto -->
|
||||||
<v-data-table
|
<v-card-text style="flex:1 1 auto; min-height:0; overflow-y:auto;">
|
||||||
:headers="bedSchedule.scheduleHeaders"
|
<div style="min-height:0;">
|
||||||
:items="bedSchedule.selectedBed?.schedules || []"
|
<v-data-table
|
||||||
class="elevation-1"
|
:headers="bedSchedule.scheduleHeaders"
|
||||||
dense
|
:items="bedSchedule.selectedBed?.schedules || []"
|
||||||
hide-default-footer
|
:items-per-page="9999"
|
||||||
:items-per-page="5"
|
class="elevation-1"
|
||||||
>
|
dense
|
||||||
<template #item.scheduleDate="{item}">
|
hide-default-footer
|
||||||
{{item.scheduledate|timeString('YYYY-MM-DD')}}
|
>
|
||||||
</template>
|
<template #item.scheduleDate="{item}">
|
||||||
<template #item.actions =" {item}">
|
{{ item.scheduledate | timeString('YYYY-MM-DD') }}
|
||||||
<a :href="'/admin/guadan/create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-primary">查看掛單</a>
|
</template>
|
||||||
</template>
|
<template #item.actions="{item}">
|
||||||
</v-data-table>
|
<a :href="'/admin/guadan/create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-primary">
|
||||||
</v-card-text>
|
查看掛單
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
<v-btn text color="primary" @click="closeBedSchedule">關閉</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn text color="primary" @click="closeBedSchedule">關閉</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
</div>
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
@@ -251,6 +264,7 @@
|
|||||||
{ text: '使用日期', value: 'scheduledate' },
|
{ text: '使用日期', value: 'scheduledate' },
|
||||||
{ text: '掛單單號', value: 'guaDanOrderNo' },
|
{ text: '掛單單號', value: 'guaDanOrderNo' },
|
||||||
{ text: '標題', value: 'title' },
|
{ text: '標題', value: 'title' },
|
||||||
|
{ text: '掛單人', value: 'usename' },
|
||||||
{ text: '查看掛單', value: 'actions' },
|
{ text: '查看掛單', value: 'actions' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -306,6 +320,14 @@
|
|||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.regions = res.data.regions;
|
this.regions = res.data.regions;
|
||||||
this.summary = res.data.summary; // 保存後端統計
|
this.summary = res.data.summary; // 保存後端統計
|
||||||
|
try {
|
||||||
|
this.regions.sort((a, b) => {
|
||||||
|
return Number(a.isStop) - Number(b.isStop);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error('API 錯誤', err);
|
console.error('API 錯誤', err);
|
||||||
@@ -381,9 +403,6 @@
|
|||||||
return { maleBeds, femaleBeds };
|
return { maleBeds, femaleBeds };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
|
|||||||
217
web/admin/region/handle_bed_in_used.aspx
Normal file
217
web/admin/region/handle_bed_in_used.aspx
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="handle_bed_in_used.aspx.cs" Inherits="admin_region_handle_bed_in_used" %>
|
||||||
|
|
||||||
|
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||||
|
</asp:Content>
|
||||||
|
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||||
|
<nav>
|
||||||
|
<div>
|
||||||
|
<label style="display: inline-block;">區域:</label>
|
||||||
|
<select style="display: inline-block; min-width:150px; max-width:20%;"
|
||||||
|
class="form-select"
|
||||||
|
v-model="selectedRegionUuid"
|
||||||
|
:disabled="isFromUrl"
|
||||||
|
@change="onRegionChange"
|
||||||
|
><option :value="null">請選擇區域</option>
|
||||||
|
<option
|
||||||
|
v-for="region in regions"
|
||||||
|
:key="region.uuid"
|
||||||
|
:value="region.uuid"
|
||||||
|
>
|
||||||
|
{{ region.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<label style="display: inline-block;margin-left: 20px;">客房:</label>
|
||||||
|
<select style="display: inline-block; min-width:200px; max-width:20%;"
|
||||||
|
class="form-select"
|
||||||
|
v-model="selectedRoomUuid"
|
||||||
|
:disabled="isFromUrl"
|
||||||
|
@change="onRoomChange"
|
||||||
|
>
|
||||||
|
<option :value="null">請選擇房間</option>
|
||||||
|
<option v-for="room in rooms" :key="room.uuid" :value="room.uuid">{{room.fullName}}</option>
|
||||||
|
</select>
|
||||||
|
<label style="display: inline-block;margin-left: 20px;">床位:</label>
|
||||||
|
<select style="display: inline-block; width:100px;"
|
||||||
|
class="form-select"
|
||||||
|
v-model="selectedBedUuid"
|
||||||
|
:disabled="isFromUrl"
|
||||||
|
></select>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</asp:Content>
|
||||||
|
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||||
|
<div>
|
||||||
|
<v-data-table
|
||||||
|
:items="items"
|
||||||
|
show-select
|
||||||
|
v-model:selected="selectedItems"
|
||||||
|
item-key="bedUuid"
|
||||||
|
|
||||||
|
:headers="headers">
|
||||||
|
<template #item.actions="{item}">
|
||||||
|
<button class="btn btn-outline-danger" type="button" @click="confirmAndCancelSingleBedBooking(item)">取消預約</button>
|
||||||
|
</template>
|
||||||
|
<template #item.guadan_during="{item}">
|
||||||
|
{{item.guadan_during.checkInAt|timeString('YYYY-MM-DD')}} - {{item.guadan_during.checkOutAt|timeString('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
|
<template #item.status="{item}">
|
||||||
|
{{item.status.name}}
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</div>
|
||||||
|
<!-- 更新修改確認彈出視窗 -->
|
||||||
|
<message-modal ref="messageModal"></message-modal>
|
||||||
|
<!-- 刪除確認彈出視窗 -->
|
||||||
|
<confirm-modal ref="confirmModal"></confirm-modal>
|
||||||
|
</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 {
|
||||||
|
|
||||||
|
regionUuidFromUrl: '<%= Request.QueryString["region"] %>' || null,
|
||||||
|
roomUuidFromUrl: '<%= Request.QueryString["room"] %>' || null,
|
||||||
|
bedUuidFromUrl: '<%= Request.QueryString["bed"] %>' || null,
|
||||||
|
// 用戶選擇的值
|
||||||
|
selectedRegionUuid: null,
|
||||||
|
selectedRoomUuid: null,
|
||||||
|
selectedBedUuid: null,
|
||||||
|
regions: [],
|
||||||
|
rooms: [],
|
||||||
|
bed: [],
|
||||||
|
selectedItems: [],
|
||||||
|
items: [],
|
||||||
|
headers: [
|
||||||
|
{ text: '床位名稱', value: 'fullName' },
|
||||||
|
{ text: '掛單號:', value: 'guaDanOrderNo' },
|
||||||
|
{ text: '掛單人', value: 'u_name' },
|
||||||
|
{ text: '掛單時間', value: 'guadan_during' },
|
||||||
|
{ text: '掛單狀態', value: 'status' },
|
||||||
|
{ text: '', value: 'actions' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onRegionChange() {
|
||||||
|
console.log("選擇的區域 UUID:", this.selectedRegionUuid);
|
||||||
|
this.selectedRoomUuid = null;
|
||||||
|
this.selectedBedUuid = null;
|
||||||
|
this.GetInUsedBed();
|
||||||
|
this.GetRoomList();
|
||||||
|
},
|
||||||
|
onRoomChange() {
|
||||||
|
console.log("選擇的客房 UUID:", this.selectedRoomUuid);
|
||||||
|
this.GetInUsedBed();
|
||||||
|
},
|
||||||
|
async GetInUsedBed() {
|
||||||
|
//獲取已經預約或者入住的床位
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
regionUuid: this.selectedRegionUuid || null,
|
||||||
|
roomUuid: this.selectedRoomUuid || null,
|
||||||
|
bedUuid: this.selectedBedUuid || null
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await axios.post(HTTP_HOST + "api/bed/inuse/list", payload);
|
||||||
|
|
||||||
|
// 假設返回的就是床位數組
|
||||||
|
this.items = response.data;
|
||||||
|
|
||||||
|
console.log("已獲取床位:");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("獲取床位失敗:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async confirmAndCancelSingleBedBooking(item) {
|
||||||
|
// 先彈出確認彈出視窗
|
||||||
|
this.$refs.confirmModal.open({
|
||||||
|
message: `確定要取消床位 ${item.name || ''} 的所有預約嗎?`,
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
bedUuid: item.bedUuid || null
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await axios.post(
|
||||||
|
HTTP_HOST + "api/bed/inuse/cancel/singlebed/booking",
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
|
||||||
|
// 刷新床位列表
|
||||||
|
this.GetInUsedBed();
|
||||||
|
|
||||||
|
// 成功提示
|
||||||
|
console.log("取消成功:", item.bedUuid);
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
title: '取消成功',
|
||||||
|
message: response?.data?.message || '取消成功!',
|
||||||
|
status: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("取消失敗:", error);
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
title: '取消失敗',
|
||||||
|
message: error.response?.data?.message || '取消過程中發生錯誤!',
|
||||||
|
status: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async CancelAllBedBooking() {
|
||||||
|
//取消符合條件的所有床位的所有預約
|
||||||
|
},
|
||||||
|
async GetRegionList() {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(
|
||||||
|
HTTP_HOST + "api/bed/inuse/region/list"
|
||||||
|
);
|
||||||
|
this.regions = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async GetRoomList() {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(
|
||||||
|
HTTP_HOST + "api/bed/inuse/room/list", {
|
||||||
|
params: {
|
||||||
|
regionUuid: this.selectedRegionUuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.rooms = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.selectedRegionUuid = this.regionUuidFromUrl;
|
||||||
|
this.selectedRoomUuid = this.roomUuidFromUrl;
|
||||||
|
this.selectedBedUuid = this.bedUuidFromUrl;
|
||||||
|
this.GetInUsedBed();
|
||||||
|
this.GetRegionList();
|
||||||
|
this.GetRoomList();
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 判斷是否來自 URL,禁用下拉框
|
||||||
|
isFromUrl() {
|
||||||
|
return this.regionUuidFromUrl || this.roomUuidFromUrl || this.bedUuidFromUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</asp:Content>
|
||||||
14
web/admin/region/handle_bed_in_used.aspx.cs
Normal file
14
web/admin/region/handle_bed_in_used.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_region_handle_bed_in_used : MyWeb.config
|
||||||
|
{
|
||||||
|
protected void Page_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,17 +15,16 @@
|
|||||||
<i class="mdi mdi-arrow-collapse-all"></i> 全部收起
|
<i class="mdi mdi-arrow-collapse-all"></i> 全部收起
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
<nav v-if="form && selectedType==null">
|
<nav v-if="createRegionFlag">
|
||||||
<button class="btn btn-primary me-2" @click="saveRegion" type="button">
|
<button class="btn btn-primary me-2" @click="saveRegion" type="button">
|
||||||
<i class="bi bi-save me-1"></i> 儲存區域資料
|
<i class="bi bi-save me-1"></i> 儲存區域資料
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
<nav class="btn-group mb-2 ps-3 pe-3" role="group" v-if="form && selectedType=='region'">
|
<nav class="btn-group mb-2 ps-3 pe-3" role="group" v-if="form && selectedType=='region' && !createRegionFlag">
|
||||||
|
|
||||||
<button class="btn btn-primary me-2" @click="saveRegion" type="button">
|
|
||||||
<i class="bi bi-save me-1"></i> 儲存區域資料
|
|
||||||
</button>
|
|
||||||
<div v-if="selectedRegionId">
|
<div v-if="selectedRegionId">
|
||||||
|
<button class="btn btn-primary me-2" @click="saveRegion" type="button">
|
||||||
|
<i class="bi bi-save me-1"></i> 儲存區域資料1
|
||||||
|
</button>
|
||||||
<button class="btn btn-success me-2" @click="createSubRegion" type="button" >
|
<button class="btn btn-success me-2" @click="createSubRegion" type="button" >
|
||||||
<i class="mdi mdi-arrow-down-right"></i> 新增下層區域
|
<i class="mdi mdi-arrow-down-right"></i> 新增下層區域
|
||||||
</button>
|
</button>
|
||||||
@@ -217,8 +216,8 @@
|
|||||||
<template #item.isactive="{item}">
|
<template #item.isactive="{item}">
|
||||||
{{item.isactive ? '啟用' : '停用'}}
|
{{item.isactive ? '啟用' : '停用'}}
|
||||||
</template>
|
</template>
|
||||||
<template #item.statusuuid="{item}">
|
<template #item.statuscode="{item}">
|
||||||
{{getBedStatusNameById(item.statusuuid)}}
|
{{getBedStatusNameById(item.statuscode)}}
|
||||||
</template>
|
</template>
|
||||||
<template #item.action ="{item}">
|
<template #item.action ="{item}">
|
||||||
<button type="button" class="btn btn-primary" @click="editBed(item)">
|
<button type="button" class="btn btn-primary" @click="editBed(item)">
|
||||||
@@ -252,8 +251,8 @@
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">狀態</label>
|
<label class="form-label">狀態</label>
|
||||||
<select class="form-control" v-model="room_bed.newBedForm.statusuuid">
|
<select class="form-control" v-model="room_bed.newBedForm.statuscode" disabled>
|
||||||
<option v-for="status in room_bed.bed_status" :value="status.uuid">
|
<option v-for="status in room_bed.bed_status" :value="status.code">
|
||||||
{{status.name}}
|
{{status.name}}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -349,6 +348,23 @@
|
|||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
|
<!-- 停用區域如果有床位正在掛單提示彈出視窗 -->
|
||||||
|
<div v-if="bed_is_used_modal" style="position:fixed; top:0; left:0; width:100%; height:100%;
|
||||||
|
background:rgba(0,0,0,0.5); display:flex; align-items:center; justify-content:center; z-index:9999;">
|
||||||
|
<div style="background:#fff; padding:20px; border-radius:8px; width:300px; text-align:center;">
|
||||||
|
<p style="margin-bottom:15px;">{{bed_is_used_modal_message}}</p>
|
||||||
|
<div style="display:flex; justify-content:flex-end; gap:10px;">
|
||||||
|
<button @click="closeBedInUsedModal"
|
||||||
|
class="btn btn-danger"
|
||||||
|
type="button" style="padding:6px 12px; border:none; border-radius:4px; cursor:pointer;">关闭</button>
|
||||||
|
<a :href="bed_is_used_modal_link" target="_blank" class="btn btn-primary">
|
||||||
|
前往处理
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 更新修改確認彈出視窗 -->
|
<!-- 更新修改確認彈出視窗 -->
|
||||||
<message-modal ref="messageModal"></message-modal>
|
<message-modal ref="messageModal"></message-modal>
|
||||||
<!-- 刪除確認彈出視窗 -->
|
<!-- 刪除確認彈出視窗 -->
|
||||||
@@ -477,13 +493,14 @@
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
vuetify: new Vuetify(vuetify_options),
|
vuetify: new Vuetify(vuetify_options),
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
bed_is_used_modal: false,
|
||||||
|
bed_is_used_modal_message: null,
|
||||||
|
bed_is_used_modal_link: "handle_bed_in_used.aspx", // 默认链接
|
||||||
selectedId: null, // 被選中項目ID
|
selectedId: null, // 被選中項目ID
|
||||||
selectedType: null, // 'region' 或 'room'
|
selectedType: null, // 'region' 或 'room'
|
||||||
expandAllFlag: false, // 控制全部展開
|
expandAllFlag: false, // 控制全部展開
|
||||||
@@ -499,6 +516,7 @@
|
|||||||
regionTypes: [],
|
regionTypes: [],
|
||||||
currentSelectRegion: null,
|
currentSelectRegion: null,
|
||||||
currentSelectRoom: null,
|
currentSelectRoom: null,
|
||||||
|
createRegionFlag: false,
|
||||||
form: {
|
form: {
|
||||||
uuid: null,
|
uuid: null,
|
||||||
name: '',
|
name: '',
|
||||||
@@ -528,7 +546,7 @@
|
|||||||
bed_headers: [
|
bed_headers: [
|
||||||
{ text: '床位編號', value: 'uuid' },
|
{ text: '床位編號', value: 'uuid' },
|
||||||
{ text: '床位名稱', value: 'name' },
|
{ text: '床位名稱', value: 'name' },
|
||||||
{ text: '床位狀態', value: 'statusuuid' },
|
{ text: '床位狀態', value: 'statuscode' },
|
||||||
{ text: '是否啟用', value: 'isactive' },
|
{ text: '是否啟用', value: 'isactive' },
|
||||||
{ text: '', value: 'action' },
|
{ text: '', value: 'action' },
|
||||||
],
|
],
|
||||||
@@ -536,7 +554,7 @@
|
|||||||
uuid: null,
|
uuid: null,
|
||||||
RegionUuid: null,
|
RegionUuid: null,
|
||||||
Name: '',
|
Name: '',
|
||||||
statusuuid: null,
|
statuscode: null,
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
Gender: null,
|
Gender: null,
|
||||||
},
|
},
|
||||||
@@ -546,6 +564,11 @@
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
closeBedInUsedModal() {
|
||||||
|
this.bed_is_used_modal = false;
|
||||||
|
this.bed_is_used_modal_message = null;
|
||||||
|
this.bed_is_used_modal_link = "handle_bed_in_used.aspx"; // 默认链接
|
||||||
|
},
|
||||||
expandAll() {
|
expandAll() {
|
||||||
this.expandAllFlag = true;
|
this.expandAllFlag = true;
|
||||||
this.collapseAllFlag = false;
|
this.collapseAllFlag = false;
|
||||||
@@ -582,6 +605,7 @@
|
|||||||
this.selectedType = 'region';
|
this.selectedType = 'region';
|
||||||
this.selectedRegionId = region.uuid;
|
this.selectedRegionId = region.uuid;
|
||||||
this.currentSelectRegion = region;
|
this.currentSelectRegion = region;
|
||||||
|
console.log(this.currentSelectRegion)
|
||||||
this.currentSelectRoom = null;
|
this.currentSelectRoom = null;
|
||||||
this.resetRoomForm();
|
this.resetRoomForm();
|
||||||
this.form = {
|
this.form = {
|
||||||
@@ -612,6 +636,8 @@
|
|||||||
this.disabledParentOptions = [];
|
this.disabledParentOptions = [];
|
||||||
this.currentSelectRegion = null;
|
this.currentSelectRegion = null;
|
||||||
this.currentSelectRoom = null;
|
this.currentSelectRoom = null;
|
||||||
|
this.createRegionFlag = true;
|
||||||
|
this.selectedType = null;
|
||||||
},
|
},
|
||||||
createSubRegion() {
|
createSubRegion() {
|
||||||
if (!this.selectedRegionId) return;
|
if (!this.selectedRegionId) return;
|
||||||
@@ -633,25 +659,39 @@
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = this.form.uuid ? '/api/region/update' : '/api/region/create';
|
const url = this.form.uuid
|
||||||
|
? HTTP_HOST + 'api/region/update'
|
||||||
|
: HTTP_HOST + 'api/region/create';
|
||||||
|
|
||||||
axios.post(url, this.form)
|
axios.post(url, this.form)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
//alert('儲存成功');
|
//alert('儲存成功');
|
||||||
this.loadRegions();
|
this.loadRegions();
|
||||||
//this.newRegion();
|
//this.newRegion();
|
||||||
this.form.uuid = res.data.uuid;
|
this.form.uuid = res.data.id;
|
||||||
this.selectedRegionId = res.data.uuid;
|
this.selectedRegionId = res.data.id;
|
||||||
this.currentSelectRegion = JSON.parse(JSON.stringify(this.form));
|
this.currentSelectRegion = JSON.parse(JSON.stringify(this.form));
|
||||||
|
this.createRegionFlag = false;
|
||||||
this.$refs.messageModal.open({
|
this.$refs.messageModal.open({
|
||||||
title: "更新",
|
title: "更新",
|
||||||
message: "更新成功",
|
message: "更新成功",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.$refs.messageModal.open({
|
console.error('更新失敗', error);
|
||||||
title: '更新提示',
|
const code = error.response?.data?.code;
|
||||||
message: error.response?.data?.message || "儲存失敗,請稍後再試。",
|
const message = error.response?.data?.message || error.message ||
|
||||||
});
|
"未知錯誤,請稍後再試";
|
||||||
|
if (code === "BED_IS_USED") {
|
||||||
|
this.bed_is_used_modal = true;
|
||||||
|
this.bed_is_used_modal_message = message
|
||||||
|
this.bed_is_used_modal_link = this.bed_is_used_modal_link + '?region=' + this.form.uuid
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
message: (message)
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
deleteRegion() {
|
deleteRegion() {
|
||||||
@@ -664,7 +704,7 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
confirmDeleteRegion() {
|
confirmDeleteRegion() {
|
||||||
axios.post('/api/region/delete', { uuid: this.form.uuid })
|
axios.post(HTTP_HOST + 'api/region/delete', { Uuid: this.form.uuid })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.showDeleteModal = false;
|
this.showDeleteModal = false;
|
||||||
this.$refs.messageModal.open({
|
this.$refs.messageModal.open({
|
||||||
@@ -716,7 +756,7 @@
|
|||||||
uuid: null,
|
uuid: null,
|
||||||
RoomUuid: this.currentSelectRoom.uuid,
|
RoomUuid: this.currentSelectRoom.uuid,
|
||||||
Name: '',
|
Name: '',
|
||||||
statusuuid: null,
|
statuscode: "101",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
Gender: this.currentSelectRoom.gender, // 不設預設值,強制選擇
|
Gender: this.currentSelectRoom.gender, // 不設預設值,強制選擇
|
||||||
};
|
};
|
||||||
@@ -731,7 +771,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
var res = await axios.post('/api/region/bed/create', this.room_bed.newBedForm);
|
var res = await axios.post(HTTP_HOST + 'api/region/bed/create', this.room_bed.newBedForm);
|
||||||
this.room_bed.showBedModal = false;
|
this.room_bed.showBedModal = false;
|
||||||
this.$refs.messageModal.open({
|
this.$refs.messageModal.open({
|
||||||
title: '成功',
|
title: '成功',
|
||||||
@@ -791,7 +831,7 @@
|
|||||||
RegionUuid: bed.regionUuid,
|
RegionUuid: bed.regionUuid,
|
||||||
RoomUuid: bed.roomUuid,
|
RoomUuid: bed.roomUuid,
|
||||||
Name: bed.name,
|
Name: bed.name,
|
||||||
statusuuid: bed.statusuuid,
|
statuscode: bed.statuscode,
|
||||||
IsActive: bed.isactive,
|
IsActive: bed.isactive,
|
||||||
Gender: bed.gender,
|
Gender: bed.gender,
|
||||||
};
|
};
|
||||||
@@ -811,7 +851,7 @@
|
|||||||
...this.room_bed.bed_items[index], // 保留原本未更新欄位
|
...this.room_bed.bed_items[index], // 保留原本未更新欄位
|
||||||
roomUuid: updated.RoomUuid,
|
roomUuid: updated.RoomUuid,
|
||||||
name: updated.Name,
|
name: updated.Name,
|
||||||
statusuuid: updated.statusuuid,
|
statuscode: updated.statuscode,
|
||||||
isactive: updated.IsActive
|
isactive: updated.IsActive
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -824,12 +864,20 @@
|
|||||||
await this.loadRegions();
|
await this.loadRegions();
|
||||||
this.room_bed.bed_items = this.currentSelectRoom.beds;
|
this.room_bed.bed_items = this.currentSelectRoom.beds;
|
||||||
//this.selectRegion(this.findRegionById(this.regions, this.form.id));
|
//this.selectRegion(this.findRegionById(this.regions, this.form.id));
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
console.log(err)
|
console.error('更新失敗', error);
|
||||||
this.$refs.messageModal.open({
|
const code = error.response?.data?.code;
|
||||||
title: '錯誤',
|
const message = error.response?.data?.message || error.message ||
|
||||||
message: err.response?.data?.message || '更新失敗'
|
"未知錯誤,請稍後再試";
|
||||||
});
|
if (code === "BED_IS_USED") {
|
||||||
|
this.bed_is_used_modal = true;
|
||||||
|
this.bed_is_used_modal_message = message;
|
||||||
|
this.bed_is_used_modal_link = this.bed_is_used_modal_link + '?bed=' + this.room_bed.newBedForm.uuid
|
||||||
|
} else {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
message: (message)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getBedStatus() {
|
getBedStatus() {
|
||||||
@@ -839,10 +887,8 @@
|
|||||||
this.room_bed.bed_status = res.data;
|
this.room_bed.bed_status = res.data;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getBedStatusNameById(id) {
|
getBedStatusNameById(statuscode) {
|
||||||
console.log(id)
|
const status = this.room_bed.bed_status.find(i => i.code == statuscode);
|
||||||
//傳入一個Id,獲取該Id對應的名稱
|
|
||||||
const status = this.room_bed.bed_status.find(i => i.uuid == id);
|
|
||||||
if (status) {
|
if (status) {
|
||||||
return status.name;
|
return status.name;
|
||||||
}
|
}
|
||||||
@@ -888,9 +934,18 @@
|
|||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('更新失敗', error);
|
console.error('更新失敗', error);
|
||||||
this.$refs.messageModal.open({
|
const code = error.response?.data?.code;
|
||||||
message: (error.response?.data?.message || error.message)
|
const message = error.response?.data?.message || error.message ||
|
||||||
});
|
"未知錯誤,請稍後再試";
|
||||||
|
if (code === "BED_IS_USED") {
|
||||||
|
this.bed_is_used_modal = true;
|
||||||
|
this.bed_is_used_modal_message = message;
|
||||||
|
this.bed_is_used_modal_link = this.bed_is_used_modal_link + '?room=' + this.room.room_form.uuid
|
||||||
|
} else {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
message: (message)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -908,6 +963,10 @@
|
|||||||
this.currentSelectRoom = null;
|
this.currentSelectRoom = null;
|
||||||
this.room_bed.bed_items = [];
|
this.room_bed.bed_items = [];
|
||||||
//清空 beds
|
//清空 beds
|
||||||
|
}).catch((error) => {
|
||||||
|
this.$refs.messageModal.open({
|
||||||
|
message: (error.response?.data?.message || error.message)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
confirmRoomDelete() {
|
confirmRoomDelete() {
|
||||||
@@ -944,7 +1003,16 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
currentSelectRegion(newVal) {
|
||||||
|
if (newVal !== null) {
|
||||||
|
this.createRegionFlag = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentSelectRoom(newVal) {
|
||||||
|
if (newVal !== null) {
|
||||||
|
this.createRegionFlag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.loadRegions();
|
this.loadRegions();
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
|
|
||||||
<div class="">
|
<div class="">
|
||||||
<a class="btn btn-outline-primary btn-print" @click="updateShuWen" v-if="currentActivityNum&&!latest">{{updateShuWenLoading ? '更新中': '更新疏文'}}</a>
|
<a class="btn btn-outline-primary btn-print" @click="updateShuWen" v-if="currentActivityNum&&!latest">{{updateShuWenLoading ? '更新中': '更新疏文'}}</a>
|
||||||
<a :href="'/api/shuwen/download?activitynum='+currentActivityNum" class="btn btn-outline-primary btn-print">下載疏文Word檔</a>
|
<a :href="'<%=ResolveUrl("~/api/shuwen/download")%>?activitynum='+currentActivityNum" class="btn btn-outline-primary btn-print">下載疏文Word檔</a>
|
||||||
</div>
|
</div>
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||||
<div v-if="currentActivityNum">
|
<div v-if="currentActivityNum">
|
||||||
<div><h2 style="text-align:center">消災疏文</h2></div>
|
<div><h2 style="text-align:center">消災疏文</h2></div>
|
||||||
<div v-for="item in ShuWenJson.xiaozai" :key="Object.keys(item)[0]">
|
<div v-for="(item, index) in ShuWenJson?.xiaozai" :key="Object.keys(item)[0] + 'xz' + index">
|
||||||
<h4>報名信眾:{{ item[Object.keys(item)[0]].user.name }}</h4>
|
<h4>報名信眾:{{ item[Object.keys(item)[0]].user.name }}</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>{{ item[Object.keys(item)[0]]['biaoti'].join(' ') }}</li>
|
<li>{{ item[Object.keys(item)[0]]['biaoti'].join(' ') }}</li>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<hr />
|
<hr />
|
||||||
</div>
|
</div>
|
||||||
<div><h2 style="text-align:center">超薦疏文</h2></div>
|
<div><h2 style="text-align:center">超薦疏文</h2></div>
|
||||||
<div v-for="item in ShuWenJson.chaodu" :key="Object.keys(item)[0]">
|
<div v-for="(item, index) in ShuWenJson?.chaodu" :key="Object.keys(item)[0] + 'cj' + index">
|
||||||
<h4>報名信眾:{{ item[Object.keys(item)[0]].user.name }}</h4>
|
<h4>報名信眾:{{ item[Object.keys(item)[0]].user.name }}</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
@@ -113,7 +113,10 @@
|
|||||||
this.ShuWenJson = {}
|
this.ShuWenJson = {}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.ShuWenJson = JSON.parse(this.ShuWenItem.shuWenList)
|
this.ShuWenJson = this.ShuWenItem?.shuWenList
|
||||||
|
? JSON.parse(this.ShuWenItem.shuWenList)
|
||||||
|
: { xiaozai: [], chaodu: [] }; // 默认空对象
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (err.response && err.response.status === 400) {
|
if (err.response && err.response.status === 400) {
|
||||||
|
|||||||
Reference in New Issue
Block a user