---
# System prepended metadata

title: 前端開發流程

---

# 前端開發流程
### 頁面介紹
![](https://i.imgur.com/898hP6K.png)

    基本的功能會有State.js、Page.vue、Main.vue、CRU.vue

> Page
> ![](https://i.imgur.com/XT5eanl.png)

> Main
> ![](https://i.imgur.com/MbspVpS.png)

> CRU
> ![](https://i.imgur.com/uT6CwAH.png)


---

### State.js

    基本的設定檔，主要放功能共用的物件，除了頁簽的url需要修改外其餘基本上都不需要修改
```javascript=37
let baseAppPath = 'pages/SYS/M1/M1002/';
const originTab = () => [defaultTabObject('常用.主單', baseAppPath + 'CRU')]
const mainTab = ref(originTab())
```
baseAppPath：功能資料夾路徑

origin：頁簽名稱跟vue的名稱

其他已經寫好的物件都有寫上註解，可以看程式決定要不要留著或修改
![](https://i.imgur.com/N2bjGyk.png)


---

### Page.vue

    最外圍的整個頁面，包含了查詢條件及filter
流程：
* 改標題名稱
* 調用Main的元件
```htmlembedded=4
<Main ref="refMain" />
```
```javascript=49
import Main from "./Main.vue";
```
```javascript=56
export default {
    components: {
        DataTable,
        ToolTip,
        Main,
    },
```
* 新增查詢條件
```htmlembedded=3
<div class="display-1">公佈欄類別功能維護</div>
<Main ref="refMain" />
<v-card color="transparent" tag="div" outlined>
    <v-card-text>
        <v-row>
            <Textbox
                col="4"
                xs="6"
                filled
                v-model="search.announcementTypeName"
                :label="
                        columnAttributeSet['announcementTypeName']
                             .displayname
                        "
            />
        </v-row>
    </v-card-text>
    <v-card-actions>
        <v-spacer />
        <Button
            color="primary"
            class="px-2"
            @click="filter.searchData()"
        >
            <v-icon left>mdi-magnify</v-icon>{{$t("常用.查詢") }}</Button
        >
        <Button
            color="grey darken-1"
            class="ma-2 mr-16"
            outlined
            @click="searchClear()"
        >{{ $t("常用.清除") }}</Button
        >
    </v-card-actions>
</v-card>
```
textbox是底層已經封好的元件，使用方法與v-textfeild差不多

label的寫法是為了要實現多國語系

announcementTypeName為欄位名稱，filter為Datatable的ref名稱
* datatable的ref名稱跟api
```htmlembedded=38
<DataTable
    ref="filter"
    :searchCondition="search"
    api_path="api/SYSM1001/filter"
>
</DataTable>
```
* 引用元件

```javascript=90
import DataTable from "@/components/common/DataTable";
import ToolTip from "@/components/common/ToolTip";
import { ApiResponseResolution } from "@/services/ApiResponseResolutionService";
import { ref, watch } from "vue";
import Main from "./Main.vue";
import State from "./State";
import api from "@/api/https";
import {
    defaultRequestInput,
    defaultColumnAttributeSetObject,
} from "@/services/CommonService";
```
ref、watch：vue的元件，詳細可以參照官方文件

defaultRequestInput：統一CRUD 功能 取得資料時使用

defaultColumnAttributeSetObject：依照傳入的item的property 產生對應的metaData 預設屬性

寫在底層的原件引用跟使用方式與上述Main.vue一樣(ex.DataTable、ToolTip、Main)
* api路徑(取得查詢的label)
```javascript=139
//取搜尋欄位多國語系的label
const columnAttributeSet = ref(
    defaultColumnAttributeSetObject(defaultItem())
);
/*API 資料方法 */
//取得columnAttribute
const getRule = async () => {
    let apiResponse = await api(
        "post",
        "api/SYSM1001/get",
        defaultRequestInput("create", "")
    );
    let itemProperty = ApiResponseResolution(apiResponse);
    //從回傳的API 寫驗證到columnAttributeSet 驗證集合
    Object.assign(
        columnAttributeSet.value,
        itemProperty.columnAttribute
    ); //欄位屬性
};
```
api串接方法為api(傳輸方法(get、post、put、delete),api路徑,回傳值)

傳接完的資料columnAttributeSet，實現查詢欄位label的多國語系

---

### Main.vue

    顯示CRUD的Dialog，主要是做分辨CURD狀態的邏輯，刪除也是寫在Main裡面
流程：
* 引用state
```javascript=95
import State from "./State";
```
```javascript=111
const {
    changeProgramStatus,
    programState,
    selectedItem,
    programStatus,
} = State();
```
* api路徑(delete)
```javascript=96
import api from "@/api/https";
```
```javascript=96
const deleteItemConfirm = async () => {
    let apiResponse = await api("put", "api/SYSM1001/deactivate", {
        ID: selectedItem.value.announcementTypeID,
    });
    let itemProperty = ApiResponseResolution(apiResponse);
    oMainCRUDUISet.value.responseMessages =
        itemProperty.responseMessages;
    if (
        !ifCertainTypeMessageExist(
            oMainCRUDUISet.value.responseMessages,
            "error"
        )
    ) {
        addDataUpdateCount();
        closeDelete();
    }
};
```

api串接方法為api(傳輸方法(get、post、put、delete),api路徑,回傳值)

---

### CRU.vue
    顯示CRU頁簽的內容，依照Main給的狀態個別顯示CRU的頁面
流程：

* 新增要修改或檢視的欄位
```htmlembedded=5
<v-form
    ref="DetailForm"
    lazy-validation
    v-model="oMainCRUDUISet.formValid"
    :readonly="!oMainCRUDUISet.editable"
>
    <v-row align="center">
        <Textbox
            xs="6"
            v-model="editedItem.announcementTypeName"
            :rules="Rule.announcementTypeName"
            :label="
                columnAttributeSet['announcementTypeName']
                    .displayname
                "
        />
        <Textbox
            xs="6"
            v-model="editedItem.sort"
            :rules="Rule.sort"
            :label="columnAttributeSet['sort'].displayname"
        />
    </v-row>
    <v-row align="center">
        <v-col cols="6">
            <v-switch
                v-model="editedItem.state"
                :label="
                    columnAttributeSet['state'].displayname +
                    '：' +
                    (editedItem.state
                        ? $t('公佈欄類別維護.已啟用')
                        : $t('公佈欄類別維護.未啟用'))
                    "
            ></v-switch>
        </v-col>
    </v-row>
</v-form>
```
* api(接欄位的資料-新增)
```javascript=96
/*API 資料方法 */
//取得FORM 驗證規則
const getRule = async () => {
    let apiResponse = await api(
        "post",
        "api/SYSM1001/get",
        defaultRequestInput(programState.value.status, "")
    );
    let itemProperty = ApiResponseResolution(apiResponse);
    //從回傳的API 寫驗證到columnAttributeSet 驗證集合
    Object.assign(
        columnAttributeSet.value,
        itemProperty.columnAttribute
    ); //欄位屬性
    await rulesGenerator(
        editedItem.value,
        columnAttributeSet.value,
        Rule.value
    ); //產生rules的結果陣列放到rule的物件
};
```
* api(接欄位的資料-查詢、檢視)
```javascript=126
//資照資料唯一流水號取得資料與驗證規則
const getItemData = async () => {
    let apiResponse = await api(
        "post",
        "api/SYSM1001/get",
        defaultRequestInput(
            programState.value.status,
            editedItem.value.announcementTypeID
        )
    );
    let itemProperty = ApiResponseResolution(apiResponse);
    Object.assign(
        columnAttributeSet.value,
        itemProperty.columnAttribute
    ); //欄位屬性
    Object.assign(editedItem.value, itemProperty.data);
        rulesGenerator(
        editedItem.value,
        columnAttributeSet.value,
        Rule.value
    ); //產生rules的結果陣列放到rule的物件
};
```
* api(儲存)
```javascript=148
//儲存
const save = async () => {
    let apiGetResponse = {};
    if (DetailForm.value.validate()) {
        let inputApiItem = {
            ...editedItem.value,
        };
        if (programState.value.status === programStatus.edit.code) {
            apiGetResponse = await api(
                "put",
                "api/SYSM1001/put",
                inputApiItem
            );
        } else if (
            programState.value.status === programStatus.create.code
        ) {
            apiGetResponse = await api(
                "post",
                "api/SYSM1001/post",
                inputApiItem
            );
        }
        let dataResult = await ApiResponseResolution(apiGetResponse); //拆資料
        Object.assign(oMainCRUDUISet.value, dataResult);
        if (
            !ifCertainTypeMessageExist(
            oMainCRUDUISet.value.responseMessages,
            "error"
            )
        ) {
            addDataUpdateCount(); //新增/編輯 會觸發dataUpdate
            if (
                programState.value.status === programStatus.create.code
            ) {
                resetMainCRUDUISet();
            }
        }
    }
};
```
* 欄位類別
1. textbox:一般的輸入框
```htmlembedded=
<Textbox
    xs="6"
    v-model="editedItem.announcementTypeName"
    :rules="Rule.announcementTypeName"
    :label="
        columnAttributeSet['announcementTypeName']
            .displayname
        "
/>
```

2. switch:類似checkbox，通常做1or0的欄位
```htmlembedded=
<v-col cols="6">
    <v-switch
        v-model="editedItem.state"
        :label="
            columnAttributeSet['state'].displayname +
            '：' +
            (editedItem.state
                ? $t('公佈欄類別維護.已啟用')
                : $t('公佈欄類別維護.未啟用'))
            "
    ></v-switch>
</v-col>
```

3. combobox:也就是autocomplete ，可以搜尋的下拉選單，需要自己在打一支api
```htmlembedded=
<Combobox
    xs="6"
    :readonly="publishStateIfNotPublish"
    v-model="editedItem.announcementTypeID"
    :items="typeIDItem"
    :rules="Rule.announcementTypeID"
    :label="
        columnAttributeSet['announcementTypeID'].displayname
        "
/>
```


4. datetimepicker:日期時間選擇器，type可以選擇只要日期或時間，預設是日期時間都有，檢視需要自己寫readonly條件
```htmlembedded=
<Datetimepicker
    :readonly="publishStateIfNotPublish"
    :date_time_val.sync="editedItem.publishSTime"
    :rules="Rule.publishSTime"
    :label="columnAttributeSet['publishSTime'].displayname"
    prepend-icon="mdi-calendar"
></Datetimepicker>
```

5. vueEditor:公佈欄的content輸入框，檢視一樣需要自己寫readonly條件

```htmlembedded=
<v-col cols="12">
    <VueEditor
        :disabled="publishStateIfNotPublish"
        model="editedItem.announcementContent"
        :rules="Rule.announcementContent"
        :label="
            columnAttributeSet['announcementContent']
                .displayname
            "
    />
</v-col>
```
![](https://i.imgur.com/6chxcnl.png)
![](https://i.imgur.com/G0X9j7e.png)
![](https://i.imgur.com/Bh8vSmr.png)
![](https://i.imgur.com/VNCY7Ee.png)
![](https://i.imgur.com/C7iib8z.png)




