從2019年開始注意到WTM,覺得代碼生成器真是能省不少事,大部分的項目都缺不了系統管理(包含用戶,用戶組,角色,角色權限,數據權限),這個通用功能WTM項目已經集成,開發者可以把主要精力投入到業務開發。對於幾個人做的小型項目,想要MVC模式開發,在這個基礎上進行開發,風格就能達到統一;
到2020年,vue版本發布了,想着現在前后端分離是前端開發熱門,就嘗試了一下,我談談我的粗淺認識。
對這個Vue版本,WTM群友的第一感覺就是前端寫出了后端的感覺,能把這個WTM-Vue版本吃透,Vue從基礎到高級用法差不多了解得差不多了。

對於初次接觸的人,Vue 的 Mixins(混入)比較費解,但要了解WTM vue2 代碼生成器生成的每個放在ClientApp/src/pages目錄下的每個窗體頁面,了解數據從webapi獲取,在前端頁面上面顯示,然后響應按鈕事件,Vue頁面的生命周期,要細細,反反復復的看form-mixin.ts,action-minxin.ts,search.ts 這幾個文件,要不都弄不清 store目錄下的api.ts 里面寫的
import { contentType } from "@/config/enum";
const reqPath = config.headerApi + "/_actionlog/";
// 列表
const search = {
url: reqPath + "Search",
method: "post",
dataType: "array"
};
// 批量刪除
const batchDelete = {
url: reqPath + "BatchDelete",
method: "post"
};
// 詳情
const detail = {
url: reqPath + "{ID}",
method: "get"
};
const exportExcel = {
url: reqPath + "ExportExcel",
method: "post",
contentType: contentType.stream
};
const exportExcelByIds = {
url: reqPath + "ExportExcelByIds",
method: "post",
contentType: contentType.stream
};
const getExcelTemplate = {
url: reqPath + "GetExcelTemplate",
method: "get",
contentType: contentType.stream
};
// 導入
const imported = {
url: reqPath + "Import",
method: "post"
};
export default {
search,
batchDelete,
detail,
exportExcel,
exportExcelByIds,
getExcelTemplate,
imported
};
這些是怎么被調用。
另外就是 ClientApp/src/components/ 下面的文件,這個可以
<template>
<wtm-dialog-box :is-show.sync="isShow" :status="status" :events="formEvent">
<wtm-create-form :ref="refName" :status="status" :options="formOptions">
</wtm-create-form>
</wtm-dialog-box>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { Action, State } from "vuex-class";
import formMixin from "@/vue-custom/mixin/form-mixin";
@Component({ mixins: [formMixin()] })
export default class Index extends Vue {
// 表單結構
get formOptions() {
return {
formProps: {
"label-width": this.$t("actionlog.LabelWidthForm")
},
formItem: {
"Entity.ID": {
isHidden: true
},
"Entity.ModuleName": {
type: "input",
label: this.$t("actionlog.ModuleName")
},
"Entity.ActionName": {
type: "input",
label: this.$t("actionlog.ActionName")
},
"Entity.ITCode": {
type: "input",
label: "ITCode"
},
"Entity.ActionUrl": {
type: "input",
label: "Url"
},
"Entity.ActionTime": {
type: "input",
label: this.$t("actionlog.ActionTime")
},
"Entity.Duration": {
type: "input",
label: this.$t("actionlog.Duration")
},
"Entity.IP": {
type: "input",
label: "IP"
},
"Entity.Remark": {
type: "input",
label: this.$t("actionlog.Remark")
}
}
};
}
}
</script>
把表單結構轉換成element組件,注意分析下 ClientApp/src/components/page/CreateForm/utils.tsx 文件,里面的generateWtmFormItemComponent 值得好好分析;
生成普通的頁面,例如下圖頁面就很容易,

但是generateWtmFormItemComponent 生成復雜頁面就力不從心,

要怎么把element組件集成到wtm-create-form里面 ,
<wtm-create-form :ref="refName" :status="status" :options="formOptions"> </wtm-create-form>
我自己是修改 ClientApp/Src/Components/page/CreateForm/index.ts
render(h) { const components = _.keys(this.options.formItem).map((key) => { const createItem=this.options.formProps["createItem"]; const item = this.options.formItem[key]; if (_.isFunction(item.isHidden)) { if (item.isHidden(this.getFormData(), this.status)) { return; } } if ((_.isBoolean(item.isHidden) && item.isHidden) || !item.type) { return; } const itemComp = componentObj[item.type]; const option = { ...item, key }; if (createItem == false) { return; } const contentComp = itemComp ? itemComp.call(this, h, option) : null; return componentObj.wtmFormItem.call(this, h, option, contentComp); }); const props = { ...this.options.formProps, disabled: this.status === "detail", model: this.sourceFormData || this.formData, }; const slots = this.$scopedSlots["default"]; if(props["createItem"]==false){ return ( <el-form ref={this.elFormRefKey} {...{ props }}> <el-row class={this.elRowClass}> {slots && slots({})} </el-row> </el-form> ); } if(props["tabs"]){ const tbpanes=props["tabs"].panes.map((key)=>{ const tbpanes_Components=components.slice(Number(key.start),Number(key.end)+1); return ( <el-tab-pane label={key.label} name={key.name}> {tbpanes_Components} </el-tab-pane> ); }); return ( <el-form ref={this.elFormRefKey} {...{ props }}> <el-row class={this.elRowClass}> <el-tabs v-model={props["tabs"].activeName} type="border-card"> {tbpanes} </el-tabs> {slots && slots({})} </el-row> </el-form> ); } else{ return ( <el-form ref={this.elFormRefKey} {...{ props }}> <el-row class={this.elRowClass}> {components} {slots && slots({})} </el-row> </el-form> ); }
其中一個用法是根據組件順序,把指定范圍的組件放到 一個 el-tab-pane,但是用到這種的情況比較少,另一個就是
<template>
<wtm-dialog-box :is-show.sync="isShow" :status="status" :events="formEvent">
<wtm-create-form :ref="refName" :status="status" :options="formOptions" :sourceFormData="mergeFormData">
<el-form-item prop="Entity.Name" :rules="formOptions.formItem['Entity.Name'].rules">
<el-input v-model="mergeFormData.Entity.Name" placeholder="請輸入庫名" @blur="blur"></el-input>
</el-form-item>
<el-form-item>
<el-input v-model="mergeFormData.Entity.Address" placeholder="請輸入地址" @blur="blur"></el-input>
</el-form-item>
</wtm-create-form>
</wtm-dialog-box>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { Action, State } from "vuex-class";
import formMixin from "@/vue-custom/mixin/form-mixin";
import UploadImg from "@/components/page/UploadImg.vue";
//:sourceFormData="mergeFormData"
@Component({
mixins: [formMixin()]
})
export default class Index extends Vue {
mergeFormData ={
Entity:{
"ID":0,
Name:"Name",
Address:"Address",
}
}
// 表單結構
get formOptions() {
const filterMethod = (query, item) => {
return item.label.indexOf(query) > -1;
};
return {
formProps: {
"label-width": "100px",
"createItem":false,
},
formItem: {
"Entity.ID": {
isHidden: true
},
"Entity.Name":{
label: "Name",
rules: [{ required: true, message:"庫名不能為空",trigger: "blur" }],
type: "input",
modifier:"trim",//v-model.trim v-model.number,v-model.lazy
slotKey:"SlotName"
},
"Entity.Address":{
label: "Address",
rules: [{ required: true, message: "地址"+this.$t("form.notnull"),trigger: "blur" }],
type: "input"
}
}
};
}
beforeRequest(formData?: object): object | void {
console.log("beforeRequest:", formData);
return formData;
}
blur(){
console.log("this.form",this.$refs[this.refName]);
console.log("blur",this.mergeFormData);
this.$refs[this.refName].setFormDataItem("Entity.Name",this.mergeFormData.Entity.Name);
this.$refs[this.refName].validate((valid) => {
if (valid) {
} else {
return false;
}
});
}
}
</script>
當 "createItem":false 時,在 wtm-create-form 里面自己綁定組件;總之Vu2版本要寫項目,還是要進行各種改造,不像 Layui版本那種綁定風格,自由度感覺受到限制;
有看過 WTM react 版本,react版本跟layUI版本的綁定比較類似,自己把實體綁定到每個組件上,后來聽說WTM vue版本要進行WTM VU3重制,我不知道了解信息有沒有錯誤,是WTM react操刀人要進行WTM vue3版本重制,我就想風格應該會跟React類似;
千呼萬喚,2021.11.18 WTMPlus Vu3版本正式發布,聽說劉總為了發布都熬通宵了;
第一時間生成幾個Model試了一下,看看有啥變化。



整個目錄結構都變了,UI也由Vue element 換成了 Vue antd,看綁定,是不是跟 layUI版本有點類似了。
<template>
<WtmDetails :queryKey="queryKey" :loading="Entities.loading" :onFinish="onFinish">
<a-row :gutter="6">
<a-col :span="12">
<WtmField entityKey="NameAdd"/>
</a-col>
<a-col :span="12">
<WtmField entityKey="Id_NoAdd"/>
</a-col>
<a-col :span="12">
<WtmField entityKey="Day_of_birthAdd"/>
</a-col>
</a-row>
<div style="text-align:right;">
</div>
<template #button>
<a-divider type="vertical" />
<a-button type="primary" html-type="submit">
<template v-slot:icon>
<SaveOutlined style='margin-right:5px'/>
</template>
<i18n-t :keypath="$locales.SysSubmit" />
</a-button>
<a-divider type="vertical" />
<a-button type="primary" @click.stop.prevent="__wtmBackDetails()">
<template v-slot:icon>
<RedoOutlined style='margin-right:5px'/>
</template>
<i18n-t :keypath="$locales.SysClose" />
</a-button>
</template>
</WtmDetails>
</template>
還剛接觸Vue3版本的,等認識更深刻后再發表看法;
最后誇一誇 WTMPlus,擁有多個微軟MVP的團隊傾力打造的低碼平台,而且項目源碼全部可以下載,開發者可以進行自由發揮,對於一個程序員,源碼在手,天下我有的感覺是不一樣的。
網址:http://wtmplus.walkingtec.cn



