提交 00ba9a10 编写于 作者: llz's avatar llz

组件-表单生成器&表格设计器完成

上级 b07d248e
......@@ -18,9 +18,8 @@
"@fullcalendar/list": "^4.4.0",
"@fullcalendar/timegrid": "^4.4.0",
"@fullcalendar/vue": "^4.4.0",
"vuedraggable": "^2.23.2",
"async-validator": "^3.3.0",
"@popperjs/core": "^2.4.3",
"async-validator": "^3.3.0",
"axios": "^0.19.1",
"core-js": "^3.4.4",
"echarts": "^4.6.0",
......@@ -30,11 +29,13 @@
"ibiz-gantt-elastic": "^1.0.17",
"ibiz-vue-lib": "^0.1.13",
"interactjs": "^1.9.4",
"js-object-pretty-print": "^0.3.0",
"moment": "^2.24.0",
"path-to-regexp": "^6.1.0",
"qs": "^6.9.1",
"rxjs": "^6.5.4",
"tinymce": "4.8.5",
"v-jsoneditor": "^1.4.1",
"view-design": "4.2.0",
"vue": "^2.6.10",
"vue-class-component": "^7.0.2",
......@@ -42,6 +43,7 @@
"vue-i18n": "^8.15.3",
"vue-property-decorator": "^8.3.0",
"vue-router": "^3.1.3",
"vuedraggable": "^2.23.2",
"vuex": "^3.1.2",
"xlsx": "^0.15.6"
},
......
因为 它太大了无法显示 源差异 。您可以改为 查看blob
此差异已折叠。
<template>
<div class="crud">
<div class="avue-crud__menu">
<div class="avue-crud__left">
<el-button-group>
<el-button type="primary"
size="medium"
@click="open('table','表格配置')">表格配置</el-button>
<el-button type="primary"
size="medium"
@click="open('menu','操作配置')">操作配置</el-button>
<el-button type="primary"
size="medium"
@click="open('dialog','弹框配置')">弹框配置</el-button>
<el-button type="primary"
size="medium"
@click="open('btn','按钮配置')">按钮配置</el-button>
</el-button-group>
</div>
<div class="avue-crud__right">
<el-button type="text"
size="medium"
icon="el-icon-document"
@click="handleAvueDoc">Avue文档</el-button>
<el-button type="text"
size="medium"
icon="el-icon-upload2"
@click="importJsonVisible = true">导入JSON</el-button>
<el-button type="text"
size="medium"
icon="el-icon-download"
@click="handleGenerateJson">保存JSON</el-button>
<el-button type="text"
size="medium"
icon="el-icon-view"
@click="handlePreview">预览</el-button>
<el-button class="danger"
type="text"
size="medium"
icon="el-icon-delete"
@click="handleClear">清空</el-button>
</div>
</div>
<!-- 配置 -->
<el-drawer :title="title"
show-close
append-to-body
size="50%"
:visible.sync="box">
<el-scrollbar style="height:100%">
<avue-form :option="tableOption"
v-model="tableForm"
v-if="type==='table'"></avue-form>
<avue-form :option="menuOption"
v-model="menuForm"
v-else-if="type==='menu'"></avue-form>
<avue-form :option="dialogOption"
v-model="dialogForm"
v-else-if="type==='dialog'"></avue-form>
<avue-form :option="btnOption"
v-model="btnForm"
v-else-if="type==='btn'"></avue-form>
</el-scrollbar>
</el-drawer>
<avue-crud :option="option"
style="margin-top:30px;"
v-model="form"
ref="crud"
@row-save="rowSave"
@row-update="rowUpdate"
@row-del="rowDel"
@sortable-change="sortableChange"
:data="list"
:before-open="beforeOpen"></avue-crud>
<!-- 导入JSON -->
<el-drawer title="导入JSON"
append-to-body
:visible.sync="importJsonVisible"
size="50%"
destroy-on-close>
<v-json-editor v-model="importJson"
height="82vh"></v-json-editor>
<div class="drawer-foot">
<el-button size="medium"
type="primary"
@click="handleImportJsonSubmit">确定</el-button>
<el-button size="medium"
type="danger"
@click="importJsonVisible = false">取消</el-button>
</div>
</el-drawer>
<!-- 生成JSON -->
<el-drawer title="生成JSON"
append-to-body
:visible.sync="generateJsonVisible"
size="50%"
destroy-on-close>
<v-json-editor v-model="widgetFormPreview"
height="82vh"></v-json-editor>
<div class="drawer-foot">
<el-button size="medium"
type="primary"
@click="handleCopy">保存</el-button>
<el-button size="medium"
type="danger"
@click="generateJsonVisible = false">取消</el-button>
</div>
</el-drawer>
<!-- 预览 -->
<el-drawer title="预览"
size="70%"
:visible.sync="drawer">
<avue-crud :option="codeOption"
:data="codeList"></avue-crud>
</el-drawer>
</div>
</template>
<script>
import { setStore, getStore } from './store'
import { option, tableOption, menuOption, dialogOption, btnOption } from './option'
import { pretty } from 'js-object-pretty-print'
import { crudDecoder } from './decoder.js'
import VJsonEditor from 'v-jsoneditor'
const Mock = require('mockjs');
export default {
name: 'crud',
components: { VJsonEditor },
data () {
return {
drawer: false,
importJsonVisible: false,
generateJsonVisible: false,
widgetFormPreview: {},
importJson: {},
title: '',
box: false,
type: '',
form: {},
activeName: 0,
tableForm: {},
tableOption: tableOption,
menuForm: {},
menuOption: menuOption,
dialogForm: {},
dialogOption: dialogOption,
btnForm: {},
btnOption: btnOption,
option: option,
list: [],
optionData: ''
}
},
props:{
colOptions:{
type: Array
}
},
created () {
},
mounted(){
},
computed: {
codemirror () {
return this.$refs.myCm.codemirror
},
codeList () {
let list = [];
//const Mock = window.Mock;
for (let i = 0; i < 10; i++) {
let obj = {};
this.list.forEach(ele => {
let result = '';
if (ele.type == 'number') {
result = Mock.mock({
"number|1-100": 100
})
} else {
result = Mock.mock('@cname');
}
obj[ele.prop] = result
})
list.push(obj)
}
return list
},
codeOption () {
let jsStr = this.code();
var jsObj = eval('(' + jsStr + ')');
return jsObj
},
},
watch: {
optionData (value) {
let columnOb = eval('(' + value + ')');//转换页面js回 option 对象
let optionObj = crudDecoder.decode(columnOb);
this.list = optionObj;
},
colOptions (value) {
if(value){
this.list = value;
}
},
list(value){
if(value.length > 0){
if(value){
this.$emit('change',value);
}
}
}
},
methods: {
// 生成JSON - 弹窗
handleGenerateJson () {
this.widgetFormPreview = this.codeOption;
this.generateJsonVisible = true;
},
// 导入JSON - 弹窗 - 确定
handleImportJsonSubmit () {
this.list = this.importJson.column;
this.importJsonVisible = false
},
// 生成JSON - 弹窗 - 拷贝
handleCopy () {
this.$emit('listChange',this.widgetFormPreview);
console.log(this.widgetFormPreview);
},
// 清空
handleClear () {
if (this.list.length !== 0) {
this.$confirm('确定要清空吗?', '警告', {
type: 'warning'
}).then(() => {
this.list = [];
})
} else this.$message.error("没有需要清空的内容")
},
handleAvueDoc () {
window.open('https://avuejs.com/doc/crud/crud-doc', '_blank')
},
handlePreview () {
this.drawer = true;
},
code () {
function vaild (option = {}, ele = '') {
const result = option[ele] + '' || '';
return !result || ele.includes('$')
}
let option = {};
option = this.deepClone(Object.assign(this.tableForm, this.menuForm, this.dialogForm, this.btnForm
) || {});
Object.keys(option).forEach(ele => {
if (vaild(option, ele)) delete option[ele];
})
option.column = this.deepClone(this.list || []);
option.column.forEach(ele => {
Object.keys(ele).forEach(key => {
if (vaild(ele, key)) delete ele[key];
})
})
let jsStr = pretty(option, 4, "PRINT", true)//stringifyObject(option)// JSON.stringify(option, null, 4);
this.optionData = jsStr;
return jsStr;
},
beforeOpen (done) {
done();
},
open (type, title) {
this.title = title;
this.type = type;
this.box = true;
},
sortableChange (oldindex, ) {
const oldrow = this.list.splice(oldindex, 1)[0];
this.list.splice(oldindex, 1, oldrow)
},
resetForm (row) {
Object.keys(row).forEach(ele => {
if (ele.includes('$')) delete row[ele];
})
return row;
},
rowDel (row, index) {
this.$confirm('是否删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.list.splice(index, 1);
}).catch(() => {
});
},
rowUpdate (row, index, done) {
this.list.splice(index, 1, row);
done();
},
rowSave (row, done) {
this.list.push(row)
done();
}
}
}
</script>
<style scoped >
.drawer-foot {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 20px;
display: flex;
}
.drawer-foot .el-button {
flex: 1;
}
</style>
import { option } from './option'
import { dicList } from './dic'
import { deepClone } from './deepClone'
export const crudDecoder = {
getOptionKV: function() {
// option.column
let kvObj = new Object();
let selectTypeList = new Array()
option.group.forEach(ele => {
if (ele.hasOwnProperty('column')) {
ele.column.forEach(e => {
// console.log(JSON.stringify(e))
kvObj[e.prop] = "";
if (e.type === 'select') {
selectTypeList.push(e.prop);
}
})
}
})
selectTypeList.forEach(e => {
kvObj['$' + e] = "";
})
return kvObj;
},
//根据输入框类型填充
prefillDicList: (ele) => {
if (ele.hasOwnProperty("type") && ele.type.length > 0) {
for (let i = 0; i < dicList.length; i++) {
let item = dicList[i];
// console.log(JSON.stringify(item))
if (item.value === ele.type) {
ele['$' + ele.type] = item.label
break;
}
}
} else {
ele['type'] = 'input'
ele['$type'] = "输入框"
}
Object.keys(ele).forEach(e => {
if (e.includes('$')) {
let key = e.replace("$", "")
if (ele[key] === 'true') {
ele[e] = '是'
} else if (ele[key] === 'true') {
ele[e] = '否'
}
}
})
//console.log("prefillDicList:"+JSON.stringify(ele))
},
decode: function(opt, boolAsStr = false) { //boolAsStr bool 是否按字符串处理,默认不按字符处理
// console.log(opt)
if (Object.keys(opt).length == 0) return;
var column = opt.column;
let objList = new Array()
let optKV = this.getOptionKV();
for (var i = 0; i < column.length; i++) {
var e = column[i];
let obj = deepClone(optKV);
Object.keys(e).forEach(key => {
// console.log("key:"+key+","+e[key])
if (boolAsStr && (e[key] === true || e[key] === false)) { //boolean 转为字符串方式,不然form 的select 报错
e[key] = "" + e[key]
}
obj[key] = e[key];
})
this.prefillDicList(obj)
objList.push(obj)
}
//console.log("decoder decode:"+JSON.stringify(objList))
return objList;
}
}
\ No newline at end of file
export const deepClone = data => {
var type = getObjType(data);
var obj;
if (type === 'array') {
obj = [];
} else if (type === 'object') {
obj = {};
} else {
//不再具有下一层次
return data;
}
if (type === 'array') {
for (var i = 0, len = data.length; i < len; i++) {
obj.push(deepClone(data[i]));
}
} else if (type === 'object') {
for (var key in data) {
obj[key] = deepClone(data[key]);
}
}
return obj;
};
export const getObjType = obj => {
var toString = Object.prototype.toString;
var map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object'
};
if (obj instanceof Element) {
return 'element';
}
return map[toString.call(obj)];
};
\ No newline at end of file
export const dicList = [{
label: '输入框',
value: 'input'
}, {
label: '选择框',
value: 'select'
}, {
label: '密码框',
value: 'password'
}, {
label: '数字框',
value: 'number'
}, {
label: '上传框',
value: 'upload'
}, {
label: '颜色选择器',
value: 'color'
}, {
label: '图标选择器',
value: 'icon-select'
}, {
label: '树框',
value: 'tree'
}, {
label: '单选框',
value: 'radio'
}, {
label: '多选',
value: 'checkbox'
}, {
label: '开关框',
value: 'switch'
}, {
label: '文本框',
value: 'textarea'
}, {
label: '时间框',
value: 'time'
}, {
label: '时间范围',
value: 'timerange'
}, {
label: '级联框',
value: 'cascader'
}, {
label: '日期框',
value: 'date'
}, {
label: '日期时间框',
value: 'datetime'
}, {
label: '日期时间范围',
value: 'datetimerange'
}, {
label: '多个日期',
value: 'dates'
}, {
label: '月',
value: 'month'
}, {
label: '周',
value: 'week'
}, {
label: '年',
value: 'year'
}]
export const ynList = [{
label: '否',
value: 'false'
}, {
label: '是',
value: 'true'
}]
export const alignList = [{
label: '居左',
value: 'left'
}, {
label: '居中',
value: 'center'
}, {
label: '居右',
value: 'right'
}]
\ No newline at end of file
import { dicList, ynList, alignList } from './dic';
export const menuOption = {
menuBtn: false,
column: [{
label: '显示',
prop: 'menu',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '宽度',
prop: 'menuWidth',
type: 'input',
span: 24
}, {
label: '对齐方式',
prop: 'menuAlign',
type: 'select',
dicData: alignList,
span: 24
}, {
label: '按钮类型',
prop: 'menuType',
type: 'select',
dicData: [
{
label: 'button',
value: 'button'
}, {
label: 'icon',
value: 'icon'
}, {
label: 'text',
value: 'text'
}, {
label: 'menu',
value: 'menu'
}
],
span: 24
}]
}
export const dialogOption = {
menuBtn: false,
column: [{
label: '宽度',
prop: 'dialogWidth',
type: 'input',
span: 24
}, {
label: '高度',
prop: 'dialogHeight',
type: 'input',
span: 24
}, {
label: '类型',
prop: 'dialogType',
type: 'select',
dicData: [{
label: '弹窗',
value: 'dialog'
}, {
label: '抽屉',
value: 'drawer'
}],
span: 24
}, {
label: '顶部距离',
prop: 'dialogTop',
type: 'input',
span: 24
}, {
label: '全屏',
prop: 'dialogFullscreen',
type: 'select',
span: 24,
dicData: ynList
}, {
label: 'esc关闭',
prop: 'dialogEscape',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '遮罩',
prop: 'dialogModal',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '遮罩关闭',
prop: 'dialogClickModal',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '关闭按钮',
prop: 'dialogCloseBtn',
type: 'select',
span: 24,
dicData: ynList
}]
}
export const btnOption = {
menuBtn: false,
column: [{
label: '新增按钮',
prop: 'addBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '编辑按钮',
prop: 'editBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '查看按钮',
prop: 'viewBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '删除按钮',
prop: 'delBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '保存按钮',
prop: 'saveBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '保存文案',
prop: 'saveBtnTitle',
span: 24,
}, {
label: '更新按钮',
prop: 'updateBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '更新文案',
prop: 'updateBtnTitle',
span: 24,
}, {
label: '取消按钮',
prop: 'cancelBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '取消文案',
prop: 'cancelBtnTitle',
span: 24,
}, {
label: '搜索按钮',
prop: 'searchBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '刷新按钮',
prop: 'refreshBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '过滤按钮',
prop: 'filterBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '打印按钮',
prop: 'printBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '导出按钮',
prop: 'excelBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '显隐按钮',
prop: 'columnBtn',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '日期按钮',
prop: 'dateBtn',
type: 'select',
span: 24,
dicData: ynList
}]
}
export const tableOption = {
menuBtn: false,
column: [{
label: '主键',
prop: 'rowKey',
span: 24,
}, {
label: '提示',
prop: 'tip',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '序号',
prop: 'index',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '多选',
prop: 'selection',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '边框',
prop: 'border',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '折叠',
prop: 'expand',
type: 'select',
span: 24,
dicData: ynList
}, {
label: '表头对其',
prop: 'headerAlign',
type: 'select',
span: 24,
dicData: alignList
}, {
label: '对其方式',
prop: 'align',
type: 'select',
span: 24,
dicData: alignList
}]
}
export const option = {
dialogType: 'drawer',
//dialogWidth: 800,
labelWidth: 100,
refreshBtn: false,
dragHandler: true,
sortable: true,
group: [{
label: '基本参数',
prop: 'jbcs',
column: [
{
label: '名称',
prop: 'label',
rules: [
{ required: true, message: '请输入名称', trigger: 'change' }
]
}, {
label: 'prop值',
prop: 'prop',
rules: [
{ required: true, message: '请输入名称', trigger: 'change' }
]
}, {
label: '类型',
prop: 'type',
type: 'select',
dicData: dicList,
rules: [
{ required: true, message: '请选择类型', trigger: 'change' }
]
}
]
}, {
label: '位置设置',
prop: 'wzsz',
column: [{
label: 'span',
prop: 'span'
}, {
label: 'gutter',
prop: 'gutter'
}, {
label: 'size',
prop: 'size'
}]
}, {
label: '表格属性',
prop: 'bgsx',
column: [
{
label: '宽度',
prop: 'width',
type: 'input'
}, {
label: '最小宽度',
prop: 'minwidth',
type: 'input'
}, {
label: '对其方式',
prop: 'align',
type: 'select',
dicData: alignList
}, {
label: '冻结',
prop: 'fixed',
type: 'select',
dicData: ynList
}, {
label: '隐藏',
prop: 'hide',
type: 'select',
dicData: ynList
},
{
label: '超出省略',
prop: 'overHidden',
type: 'select',
dicData: ynList
}, {
label: '筛选',
prop: 'filter',
type: 'select',
dicData: ynList
}, {
label: '搜索',
prop: 'search',
type: 'select',
dicData: ynList
}
]
}, {
label: '字典属性',
prop: 'zdsx',
column: [{
label: '字典类型',
prop: 'dataType',
type: 'select',
dicData: [{
label: '数字',
value: 'number'
}, {
label: '字符串',
value: 'string'
}]
}]
}, {
label: '表单属性',
prop: 'bdsx',
column: [{
label: '辅助语',
prop: 'placeholder',
}, {
label: '提示语',
prop: 'tip',
}, {
label: '新增显示',
prop: 'addDisplay',
type: 'select',
dicData: ynList
}, {
label: '编辑显示',
prop: 'editDisplay',
type: 'select',
dicData: ynList
}, {
label: '新增禁止',
prop: 'addDisabled',
type: 'select',
dicData: ynList
}, {
label: '编辑禁止',
prop: 'editDisabled',
type: 'select',
dicData: ynList
}, {
label: '只读',
prop: 'readonly',
type: 'select',
dicData: ynList
}, {
label: '最大行',
prop: 'maxRows',
type: 'input',
}, {
label: '最小行',
prop: 'minRows',
type: 'input',
}, {
label: '多选',
prop: 'multiple',
type: 'select',
dicData: ynList,
}, {
label: '精度',
prop: 'precision',
type: 'input',
}, {
label: '日期格式化',
prop: 'format'
}, {
label: '日期格式化值',
prop: 'valueFormat'
}]
}],
column: [
{
label: '名称',
prop: 'label',
display: false
}, {
label: 'prop值',
prop: 'prop',
display: false
}, {
label: '类型',
prop: 'type',
type: 'select',
dicData: dicList,
display: false
}
],
}
\ No newline at end of file
import {
validatenull
} from './validate';
const keyName = 'avue-';
/**
* 存储localStorage
*/
export const setStore = (params = {}) => {
let {
name,
content,
type,
} = params;
name = keyName + name
let obj = {
dataType: typeof(content),
content: content,
type: type,
datetime: new Date().getTime()
}
if (type) window.sessionStorage.setItem(name, JSON.stringify(obj));
else window.localStorage.setItem(name, JSON.stringify(obj));
}
/**
* 获取localStorage
*/
export const getStore = (params = {}) => {
let {
name,
debug
} = params;
name = keyName + name
let obj = {},
content;
obj = window.sessionStorage.getItem(name);
if (validatenull(obj)) obj = window.localStorage.getItem(name);
if (validatenull(obj)) return;
try {
obj = JSON.parse(obj);
} catch {
return obj;
}
if (debug) {
return obj;
}
if (obj.dataType == 'string') {
content = obj.content;
} else if (obj.dataType == 'number') {
content = Number(obj.content);
} else if (obj.dataType == 'boolean') {
content = eval(obj.content);
} else if (obj.dataType == 'object') {
content = obj.content;
}
return content;
}
/**
* 删除localStorage
*/
export const removeStore = (params = {}) => {
let {
name,
type
} = params;
name = keyName + name
if (type) {
window.sessionStorage.removeItem(name);
} else {
window.localStorage.removeItem(name);
}
}
/**
* 获取全部localStorage
*/
export const getAllStore = (params = {}) => {
let list = [];
let {
type
} = params;
if (type) {
for (let i = 0; i <= window.sessionStorage.length; i++) {
list.push({
name: window.sessionStorage.key(i),
content: getStore({
name: window.sessionStorage.key(i),
type: 'session'
})
})
}
} else {
for (let i = 0; i <= window.localStorage.length; i++) {
list.push({
name: window.localStorage.key(i),
content: getStore({
name: window.localStorage.key(i),
})
})
}
}
return list;
}
/**
* 清空全部localStorage
*/
export const clearStore = (params = {}) => {
let { type } = params;
if (type) {
window.sessionStorage.clear();
} else {
window.localStorage.clear()
}
}
\ No newline at end of file
/**
* Created by jiachenpan on 16/11/18.
*/
export function isvalidUsername(str) {
const valid_map = ['admin', 'editor']
return valid_map.indexOf(str.trim()) >= 0
}
/* 合法uri*/
export function validateURL(textval) {
const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
return urlregex.test(textval)
}
/**
* 邮箱
* @param {*} s
*/
export function isEmail(s) {
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
}
/**
* 手机号码
* @param {*} s
*/
export function isMobile(s) {
return /^1[0-9]{10}$/.test(s)
}
/**
* 电话号码
* @param {*} s
*/
export function isPhone(s) {
return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
}
/**
* URL地址
* @param {*} s
*/
export function isURL(s) {
return /^http[s]?:\/\/.*/.test(s)
}
/* 小写字母*/
export function validateLowerCase(str) {
const reg = /^[a-z]+$/
return reg.test(str)
}
/* 大写字母*/
export function validateUpperCase(str) {
const reg = /^[A-Z]+$/
return reg.test(str)
}
/* 大小写字母*/
export function validatAlphabets(str) {
const reg = /^[A-Za-z]+$/
return reg.test(str)
}
/*验证pad还是pc*/
export const vaildatePc = function() {
const userAgentInfo = navigator.userAgent;
const Agents = ["Android", "iPhone",
"SymbianOS", "Windows Phone",
"iPad", "iPod"
];
let flag = true;
for (var v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
/**
* validate email
* @param email
* @returns {boolean}
*/
export function validateEmail(email) {
const re = /^(([^<>()\\[\]\\.,;:\s@"]+(\.[^<>()\\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return re.test(email)
}
/**
* 判断身份证号码
*/
export function cardid(code) {
let list = [];
let result = true;
let msg = '';
var city = {
11: "北京",
12: "天津",
13: "河北",
14: "山西",
15: "内蒙古",
21: "辽宁",
22: "吉林",
23: "黑龙江 ",
31: "上海",
32: "江苏",
33: "浙江",
34: "安徽",
35: "福建",
36: "江西",
37: "山东",
41: "河南",
42: "湖北 ",
43: "湖南",
44: "广东",
45: "广西",
46: "海南",
50: "重庆",
51: "四川",
52: "贵州",
53: "云南",
54: "西藏 ",
61: "陕西",
62: "甘肃",
63: "青海",
64: "宁夏",
65: "新疆",
71: "台湾",
81: "香港",
82: "澳门",
91: "国外 "
};
if (!validatenull(code)) {
if (code.length == 18) {
if (!code || !/(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(code)) {
msg = "证件号码格式错误";
} else if (!city[code.substr(0, 2)]) {
msg = "地址编码错误";
} else {
//18位身份证需要验证最后一位校验位
code = code.split('');
//∑(ai×Wi)(mod 11)
//加权因子
var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
//校验位
var parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2, 'x'];
var sum = 0;
var ai = 0;
var wi = 0;
for (var i = 0; i < 17; i++) {
ai = code[i];
wi = factor[i];
sum += ai * wi;
}
if (parity[sum % 11] != code[17]) {
msg = "证件号码校验位错误";
} else {
result = false;
}
}
} else {
msg = "证件号码长度不为18位";
}
} else {
msg = "证件号码不能为空";
}
list.push(result);
list.push(msg);
return list;
}
/**
* 判断手机号码是否正确
*/
export function isvalidatemobile(phone) {
let list = [];
let result = true;
let msg = '';
var isPhone = /^0\d{2,3}-?\d{7,8}$/;
//增加134 减少|1349[0-9]{7},增加181,增加145,增加17[678]
if (!validatenull(phone)) {
if (phone.length == 11) {
if (isPhone.test(phone)) {
msg = '手机号码格式不正确';
} else {
result = false;
}
} else {
msg = '手机号码长度不为11位';
}
} else {
msg = '手机号码不能为空';
}
list.push(result);
list.push(msg);
return list;
}
/**
* 判断姓名是否正确
*/
export function validatename(name) {
var regName = /^[\u4e00-\u9fa5]{2,4}$/;
if (!regName.test(name)) return false;
return true;
}
/**
* 判断是否为整数
*/
export function validatenum(num, type) {
let regName = /[^\d.]/g;
if (type == 1) {
if (!regName.test(num)) return false;
} else if (type == 2) {
regName = /[^\d]/g;
if (!regName.test(num)) return false;
}
return true;
}
/**
* 判断是否为小数
*/
export function validatenumord(num, type) {
let regName = /[^\d.]/g;
if (type == 1) {
if (!regName.test(num)) return false;
} else if (type == 2) {
regName = /[^\d.]/g;
if (!regName.test(num)) return false;
}
return true;
}
/**
* 判断是否为空
*/
export function validatenull(val) {
if (typeof val == 'boolean') {
return false;
}
if (typeof val == 'number') {
return false;
}
if (val instanceof Array) {
if (val.length == 0) return true;
} else if (val instanceof Object) {
if (JSON.stringify(val) === '{}') return true;
} else {
if (val == 'null' || val == null || val == 'undefined' || val == undefined || val == '') return true;
return false;
}
return false;
}
\ No newline at end of file
.avue-component{
border:1px solid #f0f0f0;
padding:5px;
}
\ No newline at end of file
<template>
<div class="avue-component">
<div v-if="type === 'DynamicForm'">
<avue-form-design class="app-form-design" style="height: 86vh;" :options="formOpt" @change="handleChange"></avue-form-design>
</div>
<div v-else-if="type === 'DynamicSubForm'">
<avue-form-design class="app-form-design" style="height: 86vh;" :options="formOpt" @change="handleChange"></avue-form-design>
</div>
<div v-else-if="type === 'DynamicGrid'">
<app-avue-crud :colOptions="tableOpt" @change="handleChange"></app-avue-crud>
</div>
</div>
</template>
<script lang="ts">
import {Vue,Component,Prop,Model,Emit,Watch,} from "vue-property-decorator";
import { Subject, Subscription } from "rxjs";
import { component } from "vue/types/umd";
import './avue-component.less';
@Component({})
export default class AvueComponent extends Vue {
@Prop() public type?: string;
@Prop() public options?: any;
@Prop() public formState!: Subject<any>;
@Prop() public name: any;
public formOpt: any = {};
public tableOpt: any = [];
public handleChange(val: any){
let value: any;
if((typeof val) === 'string'){
value = val;
}else{
value = JSON.stringify(val);
}
let params: any = {name:this.name,value:value};
this.$emit('formitemvaluechange',params);
}
/**
* 订阅对象
*
* @protected
* @type {(Subscription | undefined)}
* @memberof AvueComponent
*/
protected formStateEvent: Subscription | undefined;
public created(){
let that: any = this;
if (this.formState) {
this.formStateEvent = this.formState.subscribe(({ type, data }) => {
if (Object.is("load", type)) that.load();
});
}
}
public load(){
if(this.options){
let opt: any = this.options.replace(/[\n\r]/g,"");
if(this.type)
if(this.type.indexOf('Form') > 0){
this.formOpt = JSON.parse(opt);
}else{
this.tableOpt = JSON.parse(opt);
}
}
}
}
</script>
\ No newline at end of file
......@@ -13,6 +13,8 @@ import 'element-ui/lib/theme-chalk/index.css';
import 'view-design/dist/styles/iview.css';
import 'ibiz-vue-lib/lib/ibiz-vue-lib.css';
import '@/styles/default.less';
import '@/styles/avue.css';
import axios from 'axios';
// 模拟数据
if (process.env.NODE_ENV === 'development') {
......@@ -27,6 +29,10 @@ import { PortletComponent } from '@/portlet-register';
import store from '@/store';
import router from './router';
const win: any = window;
win.axios=axios;
Vue.use(win.AVUE);
Vue.use(win.AvueFormDesign);
Vue.config.errorHandler = function (err: any, vm: any, info: any) {
console.log(err);
}
......
此差异已折叠。
......@@ -6,6 +6,8 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<script src="../assets/js/avue.min.js"></script>
<script src="../assets/js/index.umd.min.js"></script>
</head>
<body>
<noscript>
......
import AvueComponent from './components/avue-component/avue-component.vue'
import AppAvueCrud from './components/app-avue-crud/app-avue-crud.vue'
export const UserComponent = {
install(v: any, opt: any) {
v.component('avue-component', AvueComponent);
v.component('app-avue-crud', AppAvueCrud);
}
};
\ No newline at end of file
......@@ -56,7 +56,8 @@
</i-col>
<i-col v-show="detailsModel.cfg.visible" :style="{}" :sm="{ span: 24, offset: 0 }" :md="{ span: 24, offset: 0 }" :lg="{ span: 24, offset: 0 }" :xl="{ span: 24, offset: 0 }">
<app-form-item name='cfg' :itemRules="this.rules().cfg" class='' :caption="$t('entities.dstcomponent.main_form.details.cfg')" uiStyle="DEFAULT" :labelWidth="130" :isShowCaption="true" :error="detailsModel.cfg.error" :isEmptyCaption="false" labelPos="LEFT">
<input-box v-model="data.cfg" :textareaId="this.$util.createUUID()" :disabled="detailsModel.cfg.disabled" type='textarea' textareaStyle="height:200px;" ></input-box>
<!-- <input-box v-model="data.cfg" :textareaId="this.$util.createUUID()" :disabled="detailsModel.cfg.disabled" type='textarea' textareaStyle="height:200px;" ></input-box> -->
<avue-component ref="avueCompont" @formitemvaluechange="onFormItemValueChange" name='cfg' :formState="formState" :options="data.cfg" :type="data.ctype"></avue-component>
</app-form-item>
......
......@@ -14,7 +14,7 @@ module.exports = {
port: 8111,
compress: true,
disableHostCheck: true,
// proxy: "http://127.0.0.1:8080/",
proxy: "http://localhost:8080/",
historyApiFallback: {
rewrites: [
]
......
......@@ -1224,6 +1224,11 @@
error-stack-parser "^2.0.0"
string-width "^2.0.0"
"@sphinxxxx/color-conversion@^2.2.2":
version "2.2.2"
resolved "https://registry.npm.taobao.org/@sphinxxxx/color-conversion/download/@sphinxxxx/color-conversion-2.2.2.tgz#03ecc29279e3c0c832f6185a5bfa3497858ac8ca"
integrity sha1-A+zCknnjwMgy9hhaW/o0l4WKyMo=
"@types/babel__core@^7.1.0":
version "7.1.3"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30"
......@@ -1829,6 +1834,11 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
mime-types "~2.1.24"
negotiator "0.6.2"
ace-builds@^1.4.11:
version "1.4.12"
resolved "https://registry.npm.taobao.org/ace-builds/download/ace-builds-1.4.12.tgz#888efa386e36f4345f40b5233fcc4fe4c588fae7"
integrity sha1-iI76OG429DRfQLUjP8xP5MWI+uc=
acorn-globals@^4.1.0, acorn-globals@^4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7"
......@@ -5867,6 +5877,11 @@ istanbul-reports@^2.2.6:
dependencies:
html-escaper "^2.0.0"
javascript-natural-sort@^0.7.1:
version "0.7.1"
resolved "https://registry.npm.taobao.org/javascript-natural-sort/download/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
integrity sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=
javascript-stringify@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.0.1.tgz#6ef358035310e35d667c675ed63d3eb7c1aa19e5"
......@@ -6263,6 +6278,11 @@ jest@^24.9.0:
import-local "^2.0.0"
jest-cli "^24.9.0"
jmespath@^0.15.0:
version "0.15.0"
resolved "https://registry.npm.taobao.org/jmespath/download/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217"
integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=
js-beautify@^1.6.12, js-beautify@^1.6.14:
version "1.10.3"
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.3.tgz#c73fa10cf69d3dfa52d8ed624f23c64c0a6a94c1"
......@@ -6284,6 +6304,11 @@ js-message@1.0.5:
resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.5.tgz#2300d24b1af08e89dd095bc1a4c9c9cfcb892d15"
integrity sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=
js-object-pretty-print@^0.3.0:
version "0.3.0"
resolved "https://registry.npm.taobao.org/js-object-pretty-print/download/js-object-pretty-print-0.3.0.tgz#4670e450066ee1eccf35174c7d197f5aa38bcf74"
integrity sha1-RnDkUAZu4ezPNRdMfRl/WqOLz3Q=
js-queue@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/js-queue/-/js-queue-2.0.0.tgz#362213cf860f468f0125fc6c96abc1742531f948"
......@@ -6403,6 +6428,11 @@ json-schema@0.2.3:
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.npm.taobao.org/json-source-map/download/json-source-map-0.6.1.tgz#e0b1f6f4ce13a9ad57e2ae165a24d06e62c79a0f"
integrity sha1-4LH29M4Tqa1X4q4WWiTQbmLHmg8=
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
......@@ -6432,6 +6462,20 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"
jsoneditor@^8.6.4:
version "8.6.8"
resolved "https://registry.npm.taobao.org/jsoneditor/download/jsoneditor-8.6.8.tgz#2d90aa2a4ffcc1f9069728115de58414c2fd80e4"
integrity sha1-LZCqKk/8wfkGlygRXeWEFML9gOQ=
dependencies:
ace-builds "^1.4.11"
ajv "^6.12.2"
javascript-natural-sort "^0.7.1"
jmespath "^0.15.0"
json-source-map "^0.6.1"
mobius1-selectr "^2.4.13"
picomodal "^3.0.0"
vanilla-picker "^2.10.1"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
......@@ -7084,6 +7128,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.npm.taobao.org/mkdirp/download/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha1-PrXtYmInVteaXw4qIh3+utdcL34=
mobius1-selectr@^2.4.13:
version "2.4.13"
resolved "https://registry.npm.taobao.org/mobius1-selectr/download/mobius1-selectr-2.4.13.tgz#0019dfd9f984840d6e40f70683ab3ec78ce3b5df"
integrity sha1-ABnf2fmEhA1uQPcGg6s+x4zjtd8=
mockjs@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mockjs/-/mockjs-1.1.0.tgz#e6a0c378e91906dbaff20911cc0273b3c7d75b06"
......@@ -7848,6 +7897,11 @@ picomatch@^2.0.5:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
picomodal@^3.0.0:
version "3.0.0"
resolved "https://registry.npm.taobao.org/picomodal/download/picomodal-3.0.0.tgz#facd30f4fbf34a809c1e04ea525f004f399c0b82"
integrity sha1-+s0w9PvzSoCcHgTqUl8ATzmcC4I=
pify@^2.0.0, pify@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
......@@ -10199,6 +10253,13 @@ v-click-outside-x@^3.7.1:
resolved "https://registry.yarnpkg.com/v-click-outside-x/-/v-click-outside-x-3.7.1.tgz#aa03eaa0e41e44cb5207dcf86c2d9f0dd64084c1"
integrity sha512-WmUgmcIXr9clVpm1AYS/FgHtcDicfnfoxgQCNg4O6vfk9GVnxA0vSqO321ogUo0b7czYTidj7fQENvWFMWOkUg==
v-jsoneditor@^1.4.1:
version "1.4.1"
resolved "https://registry.npm.taobao.org/v-jsoneditor/download/v-jsoneditor-1.4.1.tgz#d1a19e84c341037c6439e65c3ecb10472f77f1f9"
integrity sha1-0aGehMNBA3xkOeZcPssQRy938fk=
dependencies:
jsoneditor "^8.6.4"
validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
......@@ -10207,6 +10268,13 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
vanilla-picker@^2.10.1:
version "2.10.1"
resolved "https://registry.npm.taobao.org/vanilla-picker/download/vanilla-picker-2.10.1.tgz#b07d6df8e0c3655e39a7da11e68adc00affa2b12"
integrity sha1-sH1t+ODDZV45p9oR5orcAK/6KxI=
dependencies:
"@sphinxxxx/color-conversion" "^2.2.2"
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
......@@ -10226,10 +10294,10 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
view-design@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/view-design/-/view-design-4.1.0.tgz#8ee1c3b85f2d6969ab944c967527705d002272be"
integrity sha512-LghXI5aJUXXCbZyHIbCrXiYuEzmODef77kY2brbhRKWbT0gZzOARS7L/y8w9GnHmIUtrYtvovYEuJN+0uXxAGg==
view-design@4.2.0:
version "4.2.0"
resolved "https://registry.npm.taobao.org/view-design/download/view-design-4.2.0.tgz?cache=0&sync_timestamp=1594604683660&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fview-design%2Fdownload%2Fview-design-4.2.0.tgz#2af4865c956be84b64b25187be073016eab9a748"
integrity sha1-KvSGXJVr6EtkslGHvgcwFuq5p0g=
dependencies:
async-validator "^1.10.0"
deepmerge "^2.2.1"
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册