从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