# 前端開發流程
### 頁面介紹

基本的功能會有State.js、Page.vue、Main.vue、CRU.vue
> Page
> 
> Main
> 
> CRU
> 
---
### State.js
基本的設定檔,主要放功能共用的物件,除了頁簽的url需要修改外其餘基本上都不需要修改
```javascript=37
let baseAppPath = 'pages/SYS/M1/M1002/';
const originTab = () => [defaultTabObject('常用.主單', baseAppPath + 'CRU')]
const mainTab = ref(originTab())
```
baseAppPath:功能資料夾路徑
origin:頁簽名稱跟vue的名稱
其他已經寫好的物件都有寫上註解,可以看程式決定要不要留著或修改

---
### 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>
```




