---
title: '網頁練習 農會官網'
disqus: hackmd
---
***



***
## 目錄
[TOC]
## 開發環境
**[
Visual Studio Code](https://code.visualstudio.com/)**
### 使用語言:
***
**後端:
Python**
**前端:
HTML, CSS, JavaScript**
***
使用者故事
--
```gherkin=
Feature: Farmers' Association Website
Scenario: Accessing the Homepage
Given I am a user
When I visit the root URL of the website
Then I should be redirected to the homepage
And the relevant information based on my login status should be displayed
Scenario: User Registration
Given I am a user
When I visit the registration page
And I enter my desired username and password
And I submit the registration form
Then my account should be created and stored in the database
And I should be redirected to the login page with a success message
Scenario: User Login
Given I am a user
When I visit the login page
And I enter my username and password
And I submit the login form
Then my credentials should be validated against the stored user data in the database
And if my credentials are correct, I should be logged in
And I should be redirected to the homepage with a success message
And if my credentials are incorrect, I should be shown an error message
Scenario: User Logout
Given I am a logged-in user
When I visit the logout page or click on the logout button
Then I should be logged out of my account
And my login status should be updated in the session
And any session data related to my account should be cleared
And I should be redirected to the root URL of the website with a success message indicating successful logout
Scenario: Password Reset
Given I am a user
When I visit the "Forgot Password" page
And I enter my username
And I submit the form
Then the system should check if the entered username exists in the database
And if the username exists, I should be redirected to the "Reset Password" page
And on the "Reset Password" page, I should be able to enter a new password and confirm it
And if the new password and confirmation match, my password should be updated in the database
And I should be redirected to the homepage with a success message indicating successful password reset
Scenario: Viewing Website Sections
Given I am a user
When I visit a specific section of the website
Then the corresponding HTML template should be rendered
And any necessary data from the JSON files should be passed to the template
And the relevant information should be displayed on the page
```
> Read more about Gherkin here: https://docs.cucumber.io/gherkin/reference/
實作部分
---
### 網頁架構圖:

### 資料架構圖:

### 資料庫架構圖:

### 前端畫面設計:

> **首頁(未登入)畫面**

> **登入畫面**


> **首頁(已登入)畫面**

> **重置密碼畫面**

> **網站作者畫面**

> **投保農會名稱與地址一覽表**

> **新竹總分支機構一覽表**






> **其餘畫面**
### 資料範例--JSON

### 後端程式碼:
```python
from flask import (Flask,redirect,render_template,request,url_for,session,)
# 導入 Flask 相關模組,用於建立 Web 應用程式
from flask_bcrypt import Bcrypt # 引入 Flask-Bcrypt 擴充套件
from register import Data # 匯入自訂的 register 模組,用於處理註冊相關功能
from generate_key import Ger # 匯入自訂的 generate_key 模組,用於生成密鑰
import json # 導入 json 模組,用於處理 JSON 格式的數據
app = Flask(__name__) # 建立 Flask 應用程式實例
DATABASE = "database.db" # 資料庫檔案名稱
bcrypt = Bcrypt() # 建立 Bcrypt 實例
@app.route("/") # 路由: 根目錄
def index():
return redirect(url_for("homepage")) # 重定向到 homepage 路由
# 首頁路由
@app.route("/homepage")
def homepage():
# is_logged_in = str(session.get("login_status", 0))
is_logged_in = session.get("login_status", 0)
print("is_logged_in:", is_logged_in)
return render_template("homepage.html", is_logged_in=is_logged_in)
# 註冊路由
@app.route("/register", methods=["GET", "POST"])
def register():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
# 檢查使用者名稱是否已存在
user_exists = Data.check_user(username)
if user_exists:
error_message = "帳號已存在,請選擇其他帳號"
return redirect(url_for("register", error_message=error_message))
# 插入新使用者資料
Data.insert_user(username, password)
# 註冊成功訊息
success_message = "註冊成功!"
# 重定向到 login.html,並將註冊成功訊息作為參數傳遞
return redirect(url_for("login", success_message=success_message))
return render_template("register.html")
# 登入路由
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
is_logged_in = str(session.get("login_status", 0))
# 登入狀態正常
password_matched = Data.check_password(username, password)
if password_matched:
# 登入成功後將登入狀態存儲到會話中
# session["username"] = username
session["login_status"] = 1
# Data.update_session(username, is_logged_in)
# 登入成功訊息
success_message = "登入成功!"
return redirect(
url_for("homepage", success_message=success_message)
) # 重定向到 homepage 路由
else:
error_message = "登入失敗!"
return redirect(url_for("login", error_message=error_message))
return render_template("login.html")
# 登出路由
@app.route("/logout")
def logout():
# 執行登出操作,例如清除登入會話或狀態
session.pop("login_status", None) # 清除存儲在會話中的登入狀態信息
# 登出成功訊息
success_message = "登出成功!"
return redirect(url_for("index", success_message=success_message))
# 忘記密碼路由
@app.route("/forgot_password", methods=["GET", "POST"])
def forgot_password():
if request.method == "POST":
username = request.form["username"]
# 檢查使用者名稱是否已存在
user_exists = Data.check_user(username)
if user_exists:
return redirect(url_for("reset_password"))
else:
error_message = "使用者帳號不存在"
return redirect(url_for("register", error_message=error_message))
return render_template("forgot_password.html")
# 重置密碼路由
@app.route("/reset_password", methods=["GET", "POST"])
def reset_password():
if request.method == "POST":
username = request.form["username"]
new_password = request.form["new_password"]
confirm_password = request.form["confirm_password"]
# 檢查使用者名稱是否已存在
user_exists = Data.check_user(username)
if user_exists:
if new_password != confirm_password:
error_message = "新密碼和確認密碼不一致"
return redirect(url_for("reset_password", error_message=error_message))
final_password = new_password = confirm_password
# 新密碼和確認密碼匹配,繼續更新密碼
Data.update_password(username, final_password)
# 重置成功訊息
success_message = "重置密碼成功!"
session["login_status"] = 0
# 重定向到 login 路由,並將重置成功訊息作為參數傳遞
return redirect(url_for("homepage", success_message=success_message))
else:
error_message = "使用者帳號不存在"
return redirect(url_for("reset_password", error_message=error_message))
return render_template("reset_password.html")
# HC_branch_overview 路由
@app.route("/HC_branch_overview")
def HC_branch_overview():
# 讀取新竹市轄農會信用部總分支機構一覽表.json 文件
with open("static/data/新竹市轄農會漁會信用部總分支機構一覽表.json", "r", encoding="utf-8") as f:
data = json.load(f)
return render_template("HC_branch_overview.html", data=data)
# branch_overview 路由
@app.route("/branch_overview")
def branch_overview():
# 讀取投保農會名稱與地址一覽表.json 文件
with open("static/data/投保農會名稱與地址一覽表.json", "r", encoding="utf-8") as f:
data = json.load(f)
return render_template("branch_overview.html", data=data)
# web_author 路由
@app.route("/web_author")
def web_author():
# 讀取網站作者.json 文件
with open("static/data/網站作者.json", "r", encoding="utf-8") as f:
data = json.load(f)
return render_template("web_author.html", data=data)
# about_us 路由
@app.route("/about_us")
def about_us():
return render_template("about_us.html")
# Agric_info 路由
@app.route("/Agric_info")
def Agric_info():
return render_template("Agric_info.html")
# FA_service 路由
@app.route("/FA_service")
def FA_service():
return render_template("FA_service.html")
# rlv_Info_link 路由
@app.route("/rlv_Info_link")
def rlv_Info_link():
return render_template("rlv_Info_link.html")
# 主程序
if __name__ == "__main__":
key = Ger.generate_key(32) # 生成一個長度為 32 的隨機密鑰
app.config["SECRET_KEY"] = key # 設置Flask app的密鑰
app.run(debug=True, ssl_context=("ssl/certificate.pem", "ssl/private_key.pem")) # 使用自簽憑證進行SSL通訊
```
### 資料庫:


### 前端網頁:




> **由於內容眾多,我只貼首頁**
**HTML:**
```htmlmixed
<!DOCTYPE html>
<html>
<head>
<title>Homepage</title>
<link
rel="stylesheet"
type="text/css"
href="{{ url_for('static', filename='css/homepage.css') }}"
/>
<script src="{{ url_for('static', filename='js/homepage.js') }}"></script>
</head>
<body>
<div class="title-image-container">
<img
src="{{ url_for('static', filename='images/title.png') }}"
alt="Title Image"
/>
</div>
{% if is_logged_in == 1 %}
<div class="button-container">
<a href="{{ url_for('reset_password') }}">重置密碼</a>
<a href="{{ url_for('web_author') }}">關於網站作者</a>
<a href="{{ url_for('about_us') }}">關於本會</a>
<a href="{{ url_for('Agric_info') }}">農情資訊</a>
<a href="{{ url_for('FA_service') }}">農會服務</a>
<a href="{{ url_for('rlv_Info_link') }}">相關連結</a>
<a href="{{ url_for('branch_overview') }}">投保農會名稱與地址一覽表</a>
<a href="{{ url_for('HC_branch_overview') }}">新竹總分支機構一覽表</a>
<a
href="https://data.gov.tw/datasets/search?p=1&size=10&s=pubdate.date_desc&rft=%E8%BE%B2%E6%9C%83"
target="_blank"
>資料來源</a
>
<a href="{{ url_for('logout') }}">登出</a>
<!-- 新增的登出链接 -->
</div>
<h1>已登入</h1>
<div class="image-container">
<img id="background-image" alt="Background Image" />
</div>
{% else %}
<div class="button-container">
<a href="{{ url_for('login') }}">登入</a>
<a href="{{ url_for('register') }}">註冊</a>
<a href="{{ url_for('web_author') }}">關於網站作者</a>
<a href="{{ url_for('about_us') }}">關於本會</a>
</div>
<div class="image-container">
<img id="background-image" alt="Background Image" />
</div>
{% endif %}
</body>
</html>
```
**JS:**

**CSS:**
```css
body {
background-color: green;
/* 将网页背景颜色设置为绿色 */
text-align: center;
/* 将文本内容置中 */
}
.title-image-container {
margin-bottom: 20px;
/* 设置图片下方的边距 */
position: relative;
z-index: 2;
}
.image-container {
margin-top: 20px;
/* 设置按钮上方的边距 */
}
.image-container img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
animation: imageFade 5s infinite;
}
@keyframes imageFade {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
80% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.button-container {
margin-top: 20px;
/* 设置按钮上方的边距 */
background-color: rgba(255,255,255,0.7);
/* 调整按钮容器的背景颜色和透明度 */
padding: 10px;
/* 添加内边距以增加容器与背景图片的间距 */
display: inline-block;
/* 将链接转换为块级元素,宽度仅限于文本内容的长度 */
margin-bottom: 10px;
/* 设置链接之间的下方边距 */
position: relative;
z-index: 2;
}
```
### 補充:

> 網站使用**自簽憑證**進行SSL加密通訊
### 輸出:

### 問題:
***

**一開始想說怎麼排版(CSS)都設置好了,表格"農會名稱"那欄的資料還是無法置中**
**結果看一下json檔內容...**

**"農會名稱"跟"農會保險部地址"的資料裡{""}都有一堆連續空格...更慘的是資料有1436行!!**
**思考一陣子,決定寫個遍歷json檔並檢查""裡有連續空格就刪除的程式**

**從 輸出 跟 json檔 看來空格都被刪除了**


**再去網頁檢查表格是否如我預期**


:::info
**表格的排版問題解決了**
:::
**之後又發現檢查資料庫內容的code有點問題,請參考 "資料庫"**

**輸出只有一欄,可是我檢查.db檔,資料明明有兩筆**

**檢查一下遍歷的方法,邏輯上看起來沒有問題,執行也沒問題**

:::info
**檢查資料庫的程式碼問題尚未解決**
:::
**而"重製密碼"的部分,這裡邏輯不太正確,不能只用使用者是否記得帳號來確認身分
目前仍在嘗試用"寄送確認信"的方法做優化。**

:::info
**後端"重置密碼"部分的邏輯問題尚未優化**
:::
***
### 優化內容:
**1. 資料庫部分
2. 重置密碼部分**
> **仍在debug以及優化**
### 輸出:
> **同上**
:::info
**尚未解決問題及完善優化,有事留言!**
:::
使用者流程
---
```sequence
User->Website: 使用瀏覽器訪問網站首頁的URL
Website->User: 將使用者重新導向至首頁
Website->User: 根據登入狀態顯示相關資訊
User->Website: 訪問註冊頁面
Website->User: 顯示註冊表單
User->Website: 輸入所需的使用者名稱和密碼
User->Website: 提交註冊表單
Website->Database: 建立使用者帳號並存儲於資料庫中
Website->User: 重新導向至登入頁面並顯示成功訊息
User->Website: 訪問登入頁面
Website->User: 顯示登入表單
User->Website: 輸入使用者名稱和密碼
User->Website: 提交登入表單
Website->Database: 根據資料庫中的使用者資料驗證登入憑證
Website->User: 如果憑證正確,則登入並重新導向至首頁並顯示成功訊息
Website->User: 如果憑證不正確,則顯示錯誤訊息
User->Website: 訪問登出頁面或點擊登出按鈕
Website->User: 登出使用者並更新會話中的登入狀態
Website->User: 清除與該帳號相關的任何會話資料
Website->User: 重新導向至根URL,並顯示成功訊息表示成功登出
User->Website: 訪問「忘記密碼」頁面
Website->User: 顯示輸入使用者名稱的表單
User->Website: 輸入使用者名稱
User->Website: 提交表單
Website->Database: 檢查資料庫中是否存在輸入的使用者名稱
Website->User: 如果使用者名稱存在,則重新導向至「重設密碼」頁面
Website->User: 在「重設密碼」頁面上,允許使用者輸入新密碼並進行確認
Website->Database: 如果新密碼和確認一致,則更新資料庫中的密碼
Website->User: 重新導向至首頁,並顯示成功訊息表示成功重設密碼
User->Website: 訪問網站的特定部分
Website->User: 渲染對應的HTML模板
Website->JSON Files: 從JSON檔案中獲取必要的資料
Website->User: 在頁面上顯示相關資訊
User->Website: 結束程式(結束與網站的互動)
```
> Read more about sequence-diagrams here: http://bramp.github.io/js-sequence-diagrams/
項目時間軸
---
```mermaid
gantt
title 時間規劃
section 項目
伺服器後端開發 :2023-04-24, 30d
前端網頁開發 :2023-04-25, 30d
資料庫開發 :2023-04-24, 5d
偵錯 :2023-05-10, 20d
section 優化
尋找改善空間 :2023-05-20, 20d
成果驗收(無限期延長) :2023-06-13, 5d
```
> Read more about mermaid here: http://mermaid-js.github.io/mermaid/
## 參考資料
**[](https://data.gov.tw/)**
## 附錄&常見問題
:::info
**Find this document incomplete?** Leave a comment!
:::
###### tags: `動態網頁` `Farmers' Association` `Visual Studio Code` `HW` `憑證`