---
# System prepended metadata

title: ExamWrapper.jsx
tags: [N108 Component]

---

---
tags: N108 Component
---
# ExamWrapper.jsx
- component 切換流程圖
- 可以配合 PPT 17頁
```graphviz
digraph Pageswitch {
                nodesep=0.8
                node [color=orange, fontsize=22, shape=box]
                edge [color=RosyBrown, style=dashed]
                Exam->{Contain Wrapper}
                Wrapper->{ProblemImg Choosebtn Issue}
                Wrapper [color=orange, fontsize=22, shape=box,style=filled, fillcolor=Bisque]
}
```
## import 資料
| 名稱 | 類型 | 描述 | 來源 |
| :------ | :----------- | :----------- | :----------- |
| NavLink | <font color='RosyBrown'>external component</font> | Route | react-router-dom |
| api |  <font color='Green'>function</font> |  API function | app/lib/api.js |
| ChooseBtn | <font color='BlueViolet'>component</font> | 每個題目的選項 component | exam/ExamChoosebtn.jsx |
| Problem_img | <font color='BlueViolet'>component</font> | 每個題目的圖片容器 component | exam/ExamProblemImg.jsx |
| Detail | <font color='BlueViolet'>component</font> | 詳解頁面| detail/Detail.jsxx |
| Issue | <font color='BlueViolet'>component</font> | 詳解頁面| exam/ExamIssue.jsx |
| collectform |  <font color='Green'>function</font> |  獲取form 資料 | app/lib/collectform.jsx |
| queryString |  <font color='Green'>function</font> | query-string 擷取函數 | query-string |
| sorry | <font color='Red'>image</font> | 抱歉圖片 | image/sorry.png |
| Cbtn | <font color='BlueViolet'>component</font> | wrapper close button | tool/Closebtn.jsx |
## constructor 介紹
### state 參數介紹
| 名稱 | 類型 | 描述 | defalut |
| :------ | :----------- | :----------- | :-- |
| `data` | <font color='Gold'>json value</font> | API 傳回的題目資料| `[]` |
| `ansset` | <font color='Gold'>json value</font> | 每個題目的正確解答| `[]` |
| `inputSet` | <font color='orange'>string array</font>  | 每個題目的狀態 (對 or 錯)|`[]`|
| `myAns` | <font color='Gold'>json value</font> | 使用者回答題目的答案| `[]` |
| `submit` | <font color='blue'>bool</font> | 使用者繳交答案，終止考試| `false`  |
| `problemId` | <font color='Salmon'>int</font> | 目前在第幾題對應的 ID| `0` |
| `error` | <font color='orange'>string</font> | API 傳回的錯誤訊息|`null`|
| `isLoaded` | <font color='blue'>bool</font> | API loading，true 為 loading 完成，false 為正在 loading | `false` |
| `cid` | <font color='Salmon'>int</font> | 考卷對應的 CID| `0` |
### this.answer
- React.createRef 輸入用
## componentDidMount
1. queryString 擷取 cid
2. 執行 get_api()，並將 isLoaded = true 和 cid 存入 state
3. 有成功登入時，增加監聽事件 keydown (偵測 f5 按下提醒)
## componentDidUpdate
- 當 prevState == this.state 時，執行 get_api()，並將 isLoaded = true、submit = false、problemId = 0
## componentWillUnmount
- 有成功登入時，刪除監聽事件 keydown (偵測 f5 按下提醒)
## 獨立 function
| 名稱 | 描述 | async 是否 |
|:--|:--|:--|
|get_api()|Call API，並將資料分類存入 state|是|
|f5check()|偵測 f5 有沒有按下，有按下時，系統給予提醒|否|
|getstr()|考題圖片 NamePath 後處理，~~又是一個不在後端處理的案例~~|否|
|problemList()|建立圖片列表 div，包含：選項、題目圖片、Issue 按鈕|否|
|submit()|繳交，*介紹在下方*|否|
|nextP()|下一題的 button event function，如果沒有選擇選項則會提醒沒有選擇答案|否|
|backP()|上一題的 button event function|否|
|resetproblem()|重新設定考試相關參數 (回到第一題)，reset 功能|否|
|gotohome()|回首頁 function|否|
### submit() 介紹
- 獲取使用者點選答案
```jsx=128
let formitems = collectform(this.answer.current)
var writed = Object.getOwnPropertyNames(formitems)[this.state.problemId]
```
- 如果沒選擇答案，不能 submit
```jsx=130
if (typeof (writed) == "undefined")
    alert('請選擇答案!!!')
```
- 對答案
```jsx=133
let myAns = Object.getOwnPropertyNames(formitems).slice() //使用者解答
let YorN = []
for (var i = 0; i < myAns.length; i++) {
    if (myAns[i][1] == this.state.ansset[parseInt(myAns[i], 10)]) //判斷對錯
        YorN.push("yes")
    else
        YorN.push("no")
}
```
- 確定繳交才更新 state 資料
```jsx=142
var yes = confirm('你確定要繳交嗎？')
if (yes) {
    this.setState({
        myAns: myAns.slice(),
        inputSet: YorN.slice(),
        submit: true
    });
}
```
## API 數量表格
| 名稱 | 類型 | 描述 | 位於 |
|:--|:--|:--|:--|
|Exam/img_path?cid= + <font color='Blue'>cid</font>|<font color='LightSkyBlue'>get</font>|獲取該考卷所有的題目圖片 path，且答案額外抓出來一起存入 state|get_api()|
## render
### props (上層傳入) 參數介紹
| 名稱 | 類型 | 描述 |
| :------ | :----------- | :----------- |
| `login` | <font color='blue'>bool</font> | 登入參數，true 為登入中；false 為沒登入(訪客) | 
### 額外參數
| 名稱 | 類型 | 描述 |
| :------ | :----------- | :----------- |
| `problemList` | <font color='OrangeRed'>HTML</font> | this.problemList(data) |
- 大概長這樣
- [ExamProblemImg.jsx](https://hackmd.io/TDvYaVb4Rxmsle1jHHhseA?view)
- [ExamChoosebtn.jsx](https://hackmd.io/NHFUFxXIRJCOOMtPWLvENQ?view)
- [ExamIssue.jsx](https://hackmd.io/jVrW4AnjR2i9zXk93EDWuw?view)
```jsx=111
problemlist.push(
    <div className={`problem-containter ${this.state.problemId == i ? "" : "dis-no"}`} key={data[i].pid}>
        <Problem_img str={str}></Problem_img>
        <ChooseBtn id={i} answer={this.answer}></ChooseBtn>
        <Issue pid={data[i].pid} get_api_img={this.get_api} ></Issue>
    </div>
)
```
### return 
- 如果登入成功、沒按繳交、cid != 0 (queryString 有讀到)，都會顯示考試畫面
- 底下 HTML 太多不介紹，只說明條件
```jsx=212
login && !submit && cid != 0 &&
```
- 最後一題時，才會顯示 Submit button
```jsx=216
{problemId == problemList.length - 1 &&
```
- 第一題時，不顯示 back (上一題) button
```jsx=224
{problemId != 0 &&
```
- 非最後一題時，都會顯示 next (上一題) button，最後一題時，顯示 Submit button
```jsx=224
{problemId != problemList.length - 1 &&
```
- submit之後，顯示解答跟詳解 ➡️ [Detail.jsx](https://hackmd.io/FtBVORlmQSC-1fIoqoSa6A?view)
```jsx=237
{
    login && submit &&
    <Detail data={data} getstr={this.getstr} ans={inputSet}
        myans={myAns} ansset={ansset} f5check={this.f5check}>
    </Detail>
}
```
- 沒登入的畫面
- ![](https://i.imgur.com/wUZa3rM.png =80%x)
- 純 HTML 不介紹
```jsx=244
{
    !login &&
    <div className="dis-center" style={{ "height": "calc(80vh)" }}>
        <div className="help-map dis-center">
            <div className="help-content">
                <div className="help-header">
                    <Cbtn Clickbtn={this.gotohome}></Cbtn>
                    <h4 className="help-title" id="mySmallModalLabel">
                        <i className="fa fa-warning"></i>
                        &ensp;Warning
                    </h4>
                </div>
                <div className="help-body dis-center2 animate-top">
                    <div>
                        <div className="dis-center"><div style={{ "fontSize": "25px" }}>請登入才能開啟評測功能！</div></div>
                        <img src={sorry} alt="" />
                        <div className="dis-flex-row dis-space-between">
                            <div></div>
                            <div></div>
                            <NavLink className="warning-btn1 mouse" to="/Home">回首頁 <i className='fas fa-home'></i></NavLink>
                            <NavLink className="warning-btn2 mouse" to="/log_in">登入去 <i className='fas fa-sign-in-alt'></i></NavLink>
                            <div></div>
                            <div></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
}
```
[回上層 ExamContain.jsx](https://hackmd.io/8cLPGVhdRymXPrCLNYLuNw?view)