前端框架 V1.0.0
# 框架简介
# 框架一览
- 功能阐述
- 目录结构
# 简介
采用的vue3 + vite + element-plus技术架构
vue版本
3.2.45
, element-plus版本2.2.26
,nodejs版本16.17.0
,npm版本8.19.3
axios 基于 promise 的http请求封装
全局状态管理vuex,集中式存储管理应用的组件状态
indexedDB前端数据库,支持大量数据前端缓存
websocket,即时接收通信信息
draggable拖拽,工作台、查询条件,查询结果,表单等自定义拖拽排版
i18n国际化,支持多语言之间的切换
框架中预留了两种类型查询页demo(1.支持可配置的,2.常规的)
前端搭建私有化 npm 库:eci-tools 工具类,eci-cli 前端脚手架
# 组件封装
基于element-plus UI库的二次封装,根据用户场景,用户习惯,做功能的优化与拓展
根据业务需求进行功能性的整合封装,便于开发使用和代码维护
# 1.下拉框组件 <Eci-select />
<el-select-v2
v-model="value" // 绑定值
:options="options" // 数据
placeholder="Please select" // 输入提示
size="large" // 尺寸
:disabled="disabled" // 显隐
placement="top" // 显示位置
filterable // 输入过滤
clearable // 清空
multiple // 多选
collapse-tags // 多选tags
allow-create // 创建新项目
default-first-option // 默认选中第一条
:value-key="value.code + '|' + value.name" // 自定义绑定值
>
<template #default="{ item }">
<span style="margin-right: 8px">{{ item.code }}</span>
<span style="color: var(--el-text-color-secondary); font-size: 13px">{{ item.name }}</span>
</template>
</el-select-v2>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 使用el-select-v2组件,支持大量数据的渲染,减少浏览器负担,提升性能
- 继承原有功能(v-model绑定值,filterable是否可筛选, clearable是否清空,multiple是否多选,collapse-tags多选标签,disabled是否禁用,allow-create是否创建新项目,placement下拉框出现的位置,等等)
- 支持输入检索,默认选中第一条(default-first-option : filterable 设置为true时)
- 支持下拉框回车事件,焦点后移(focustypes,focusNext)
- 选值类型 (code + '|' + name)
# 2.输入框组件 <Eci-input />
<el-input
v-model="input" // 绑定值
placeholder="Please input"
show-password // 显示隐藏的密码框
clearable // 是否允许清空
disabled // 是否禁用
maxlength="10" // 最大长度
minlength="2" // 最短长度
/>
2
3
4
5
6
7
8
9
- 继承原有功能(v-model绑定值,maxlength 最大长度,minlength 最小长度,clearable是否清空,disabled是否禁用,show-password 是否显示隐藏的密码框等等)
- 支持输入校验,是否纯数字,是否纯字母,是否数字+字母组合等
- 支持是否数字框输入 Number (最大值,最小值,小数点保留位数,小数点是否四舍五入,controls-position控制按钮位置,controls-position控制按钮显隐)
# 3.按钮组件 <Eci-button />
<el-button
type="primary" // 样式:primary,success,info,warning,danger
plain // 边框 & 背景
link // 链接
size // 大小
:loading="loadingFlag" // 加载状态
:icon="iconName" // 支持按钮带图标
@click="singleClick" // 触发单击事件,统一做函数节流/防抖处理
>
{{ buttonName }} // 支持传入按钮名称
</el-button>
2
3
4
5
6
7
8
9
10
11
- 继承原有功能(type按钮状态颜色样式,plain 边框或背景,link 链接,size 大小等等)
- 是否带icon,支持传入icon 的名称显示
- loading 加载状态控制 布尔
# 4.表格组件(带分页功能) <Eci-table />
<el-table :data="tableData" style="width: 100%">
<slot></solt> // 传入的<el-table-column>内容
</el-table>
<el-pagination
@size-change="handleSizeChange" // 改变页数
@current-change="handleCurrentChange" // 改变页码
:current-page="paging.pageNum" // 当前页数
:page-sizes="paging.SECH_PAGE_SIZES" // 当前页数选择 数组 [10,20,50,100]
:page-size="paging.pageSize" // 每页条数
layout="total, sizes, prev, pager, next, jumper"
background // 背景色样式
:total="tableDataObj.total" // 总条数
/>
2
3
4
5
6
7
8
9
10
11
12
13
- 使用插槽,接收表格列内容(slot, el-table-column)
- 带分页功能,分页功能支持自定义(显示隐藏,样式,大小等)
# 5.导入组件 <ImportComGlobal />
- 维护对应导入传入的业务类型
- 页面使用 $openImportCom('业务类型')
// 导入统一函数
const openImportCom = (bizType, platNo) => {
if (!platNo && platNo !== undefined) {
customElement.warning('请保存表头')
return
}
let options = {
bizType: importMap[bizType], // 对应导入配置的业务类型
asUse: 1,
bizNo: platNo || '',
sysCode: window.global.importSys, // 对应配置平台系统代码
other: { _CentreImportConfigDBID: window.global.importSys, "Authorization": localStorage.get('gw_token') }, //对应配置平台系统代码
}
let option = JSON.stringify(options)
const exStr = Base64.encode(option) // 加密
let url = import.meta.env.VITE_IMPORT_URL
if (bizType === 'HZQD') {
url = import.meta.env.VITE_UPLOADURL_URL
}
url += "/" + exStr + "&strToken=" + localStorage.get('gw_userinfo').ssoToken
window.open(url, '_blank')
// window.open(url, "导入数据", "left=0")
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 6.导出组件 <ExcelExportTask />
- 组件包含导出按钮
- 页面引用 <ExcelExportTask :excelData="exportData" />,传入导出数据exportData
// 导出到excel
const downloadExl = (json, downName) => {
let keyMap = []; // 获取键
for (let k in json[0]) {
keyMap.push(k);
}
let tmpdata = []; // 用来保存转换好的json
json.map((v, i) => keyMap.map((k, j) => Object.assign({},
{
v: v[k],
position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
}))).reduce((prev, next) => prev.concat(next)).forEach(function (v) { tmpdata[v.position] = { v: v.v } }
)
let outputPos = Object.keys(tmpdata) // 设置区域,比如表格从A1到D10
let tmpWB = {
SheetNames: ["mySheet"], // 保存的表标题
Sheets: {
mySheet: Object.assign({}, tmpdata, // 内容
{
"!ref": outputPos[0] + ":" + outputPos[outputPos.length - 1], // 设置填充区域
}
)
}
}
let tmpDown = new Blob(
[
s2ab(
XLSX.write(
tmpWB,
{
bookType: "xlsx",
bookSST: false,
type: "binary",
} // 这里的数据是用来定义导出的格式类型
)
),
],
{ type: '' }
) // 创建二进制对象写入转换好的字节流
if ("msSaveOrOpenBlob" in window.navigator) {
window.navigator.msSaveOrOpenBlob(tmpDown, downName + ".xlsx")
} else {
var href = URL.createObjectURL(tmpDown) // 创建对象超链接
state.outFile.download = downName + ".xlsx" // 下载名称
state.outFile.href = href // 绑定a标签
state.outFile.click() // 模拟点击实现下载
setTimeout(function () {
URL.revokeObjectURL(tmpDown) // 用URL.revokeObjectURL()来释放这个object URL
}, 100);
state.loading = false
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 7.图片上传 <ImagesUpload />
- isOpenAliyunUpload: true, // windows.global 是否开启阿里云图片上传
- 页面使用,传入按钮名称,组件返回图片url
// 页面调用
<ImagesUpload
btnNames="上传签名"
@getImageUploadUrl="getImageUploadUrl($event, 'signUrl')"
/>
2
3
4
5
# 工具类封装(npm库)
采用面向对象的以及纯函数的设计思想,将单一的功能设计成纯函数,纯函数具有行为一致,无副作用,适合统一的工具方法封装。结合主工具类,以及入口工厂函数,方便后期做工具库的配置以及扩展。
# 1.函数节流
/**
* 创建并返回一个像节流阀一样的函数,当重复调用函数的时候,最多每隔delay毫秒调用一次该函数
* @author Jerome.luo
* @date 2023/02/03
* @param fn 执行函数, delay 时间间隔
* @returns {Function}
*/
const throttle = (fn, delay) => {
var timer = null
var timeStamp = new Date()
return function() {
var context = this //获取函数所在作用域this
var args = arguments //取得传入参数
if (new Date() - timeStamp > delay) {
timeStamp = new Date()
timer = setTimeout(function(){
fn.apply(context, args)
}, delay)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2.函数防抖
/**
* 防反跳。fn函数在最后一次调用时刻的delay毫秒之后执行!
* @author Jerome.luo
* @date 2023/02/03
* @param fn 执行函数 delay 时间间隔
* @param isImmediate 为true,debounce会在delay时间间隔的开始时立即调用这个函数
* @returns { Function }
*/
const debounce = (fn, delay, isImmediate) => {
var timer = null //初始化timer,作为计时清除依据
return function() {
var context = this //获取函数所在作用域this
var args = arguments //取得传入参数
clearTimeout(timer)
if(isImmediate && timer === null) {
//时间间隔外立即执行
fn.apply(context,args)
timer = 0
return
}
timer = setTimeout(function() {
fn.apply(context,args)
timer = null
}, delay)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 3.文件大小换算
/**
* 获取文件大小,换算成kb单位
* @author Jerome.luo
* @date 2023/02/03
* @params num 文件总大小
* @return { Function }
*/
const getFileSize = (num) => {
let m = num / (1024 * 1024) < 1 ? ((num / 1024).toFixed(2) + 'kb') : ((num / (1024 * 1024)).toFixed(2) + 'M')
return m
}
2
3
4
5
6
7
8
9
10
11
# 4.颜色转换
/**
* 将hex颜色 转成 rgb
* @author Jerome.luo
* @date 2023/02/03
* @params hex 当前输入的值, opacity 透明度
* @return { Object }
*/
const hexToRgba = (hex, opacity) => {
let RGBA = 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' +
parseInt('0x' + hex.slice(3, 5)) + ',' + parseInt('0x' + hex.slice(5, 7)) + ',' + opacity + ')'
return {
red: parseInt('0x' + hex.slice(1, 3)),
green: parseInt('0x' + hex.slice(3, 5)),
blue: parseInt('0x' + hex.slice(5, 7)),
rgba: RGBA
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 5.邮箱正则校验
/**
* 邮箱正则校验
* @author Jerome.luo
* @date 2023/02/03
* @params str 输入的邮箱值 value
* @return { Boolean }
*/
const isEmail = (str) => {
// debugger
// var reg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/
var reg = /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/
return reg.test(str)
}
2
3
4
5
6
7
8
9
10
11
12
13
# 6.手机号正则校验
/**
* 手机号正则校验
* @author Jerome.luo
* @date 2023/02/03
* @params str 输入的手机号码 value
* @return { Boolean }
*/
const isMobPhoneNo = (str) => {
var reg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
return reg.test(str)
}
2
3
4
5
6
7
8
9
10
11
# 7.JSON字符串格式校验
/**
* 判断数据是否为JSON字符串格式
* @author Jerome.luo
* @date 2023/02/03
* @params str 字符串数据
* @return { Boolean }
*/
const isJSON = (str) => {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str)
if (typeof obj == 'object' && obj) {
return true
} else {
return false
}
} catch (e) {
console.log('error:' + str + '!!!' + e)
return false
}
} else {
console.log('It is not a string!')
return false
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 8.时间戳转换成日期格式
/**
* 将时间戳转换成日期格式
* @author Jerome.luo
* @date 2023/02/03
* @params timestamp 时间戳
* @return { date }
*/
const timestampToTime = (timestamp) => {
var date = new Date(timestamp) // 时间戳为10位需 * 1000,时间戳为13位的话不需乘1000
var Y = date.getFullYear() + '-'
var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'
var D = date.getDate() + ' '
var h = date.getHours() + ':'
var m = date.getMinutes() + ':'
var s = date.getSeconds()
return Y + M + D + h + m + s
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 9.日期格式化
/**
* 去掉部分列表里日期的时分秒
* @author Jerome.luo
* @date 2023/02/03
* @params time 时间数据,支持日期连接符</ . ->
* @return { date }
*/
const deleteTimeSfm = (time)=>{ // 去掉部分列表里日期的时分秒
let Newtime = '', reg = null
if (time) {
if (time.includes('-')) {
reg = /\d{4}-\d{1,2}-\d{1,2}/g
} else {
reg = /\d{4}.\d{1,2}.\d{1,2}/g
}
Newtime = reg.exec(time)
}
return Newtime && Newtime.length ? Newtime[0] : time
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 10.控件回车键跳到下一步
/**
* 控件回车键,焦点后移(目前只支持:el-input, el-select, el-input-number, 放大镜)
* @author Jerome.luo
* @date 2022/11/10
* @params $event: 当前控件dom对象, focustypes dom绑定的nanoid()
* @use 页面使用(控件添加)::focustypes="nanoid()" @keyup.native.enter="$Tools.focusNext($event)"
* @use 放大镜:加在输入框的组件内
* @return { Function }
*/
const focusNext = ($event) => {
// 输入框获取focustypes
const inputId = $event.target.attributes['focustypes'] && $event.target.attributes['focustypes'].value
// 下拉框获取focustypes
const selectId = $event.target.offsetParent.offsetParent.attributes['focustypes'] && $event.target.offsetParent.offsetParent.attributes['focustypes'].value
// 放大镜获取focustypes
const mgfId = $event.target.parentElement.offsetParent.firstElementChild.attributes['focustypes'] && $event.target.parentElement.offsetParent.firstElementChild.attributes['focustypes'].value
// 获取所有受控的组件
const enterRefArr = $event.target && $event.target.form ? $event.target.form.elements : []
let allEl = []
for (let i = 0; i < enterRefArr.length; i++) { // 过滤input后,用于获取焦点和查找使用。(date 日期控件 排除)
if (enterRefArr[i].className.includes('el-input__inner') &&
(!enterRefArr[i].offsetParent || (enterRefArr[i].offsetParent && !enterRefArr[i].offsetParent.className.includes('el-date-editor'))) &&
!enterRefArr[i].disabled
) {
allEl.push(enterRefArr[i])
}
}
// 查找当前控件的索引值
let indexs = allEl.findIndex((item, index) => {
if (inputId) { // 输入框
return item.attributes['focustypes'] &&
item.attributes['focustypes'].value === inputId
} else if (selectId) { // 下拉框
return item.offsetParent && item.offsetParent.offsetParent &&
item.offsetParent.offsetParent.attributes['focustypes'] &&
item.offsetParent.offsetParent.attributes['focustypes'].value === selectId
} else { // 放大镜
return item.offsetParent && item.offsetParent.offsetParent &&
item.offsetParent.offsetParent.firstElementChild.attributes['focustypes'] &&
item.offsetParent.offsetParent.firstElementChild.attributes['focustypes'].value === mgfId
}
})
// 执行判断下一个控件是否有值
let newNum = indexs // 存储索引,便于while循环
if (indexs === -1 || (allEl.length === (indexs + 1))) return // 如果当前控件是最后一个, 或者未绑定当前dom节点
for (let i = 0; i < allEl.length; i++) {
if (!allEl[indexs + 1].value) { // 下一个没值时,直接获取焦点
setTimeout(() => { // 延迟操作速度
allEl[indexs + 1].focus()
}, 200)
return
} else {
// while: 如果下一个有值时,继续循环
while (newNum + 1 !== allEl.length && allEl[newNum + 1].value) newNum++
if (newNum + 1 !== allEl.length) {
setTimeout(() => { // 延迟操作速度
allEl[newNum + 1].focus()
}, 200)
return
} else {
newNum = 0
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 11.indexedDB 前端数据库
/**
* 打开数据库 indexedDB
* @author Jerome.luo
* @date 2023/02/03
* @params dbName 数据名称,storeName 表名称,version 版本号
* @return { promise }
*/
const openDB = (dbName, storeName, version = initVersion) => {
return new Promise((resolve, reject) => {
let indexedDB = window.indexedDB
let db
const request = indexedDB.open(dbName, version)
request.onsuccess = function(event) {
db = event.target.result // 数据库对象
resolve(db)
}
request.onerror = function(event) {
reject(event)
}
request.onupgradeneeded = function(event) {
// 数据库创建或升级的时候会触发
console.log('onupgradeneeded')
db = event.target.result // 数据库对象
let objectStore
if (!db.objectStoreNames.contains(storeName)) {
db.createObjectStore(FIRST_LEVEL_CACHE, { keyPath: 'key' }) // 创建表
}
}
})
}
/**
* 新增数据 indexedDB
* @author Jerome.luo
* @date 2023/02/03
* @params db 数据库,storeName 表名称,version 版本号
* @return { promise }
*/
const addData = (db, storeName, data, version = initVersion) => {
return new Promise((resolve, reject) => {
let request = db.transaction([storeName], 'readwrite') // 事务对象 指定表格名称和操作模式("只读"或"读写")
.objectStore(storeName) // 仓库对象
.add(data)
request.onsuccess = function(event) {
resolve(event)
}
request.onerror = function(event) {
reject(event)
throw new Error(event.target.error)
}
})
}
/**
* 通过主键读取数据
* @author Jerome.luo
* @date 2023/02/03
* @params db 数据库,storeName 表名称,version 版本号
* @return { promise }
*/
export async function getDataByKey(db, storeName, key, version = initVersion) {
return new Promise((resolve, reject) => {
let transaction = db.transaction([storeName]) // 事务
let objectStore = transaction.objectStore(storeName) // 仓库对象
let request = objectStore.get(key)
request.onerror = function(event) {
reject(event)
}
request.onsuccess = function(event) {
resolve(request.result)
}
})
}
/**
* 通过游标读取数据
* @author Jerome.luo
* @date 2023/02/03
* @params db 数据库,storeName 表名称,version 版本号
* @return { promise }
*/
const cursorGetData = (db, storeName, version = initVersion) => {
let list = []
let store = db.transaction(storeName, 'readwrite') // 事务
.objectStore(storeName) // 仓库对象
let request = store.openCursor() // 指针对象
return new Promise((resolve, reject) => {
request.onsuccess = function(e) {
let cursor = e.target.result
if (cursor) {
// 必须要检查
list.push(cursor.value)
cursor.continue() // 遍历了存储对象中的所有内容
} else {
resolve(list)
}
}
request.onerror = function(e) {
reject(e)
}
})
}
/**
* 通过索引和游标查询记录
* @author Jerome.luo
* @date 2023/02/03
* @params db 数据库,storeName 表名称,version 版本号
* @return { promise }
*/
const cursorGetDataByIndex = (db, storeName, indexName, indexValue) => {
let list = []
let store = db.transaction(storeName, 'readwrite').objectStore(storeName) // 仓库对象
let request = store.index(indexName) // 索引对象
.openCursor(IDBKeyRange.only(indexValue)) // 指针对象
return new Promise((resolve, reject) => {
request.onsuccess = function(e) {
let cursor = e.target.result
if (cursor) {
list.push(cursor.value)
cursor.continue() // 遍历了存储对象中的所有内容
} else {
resolve(list)
}
}
request.onerror = function(ev) {
reject(ev)
}
})
}
/**
* 更新数据
* @author Jerome.luo
* @date 2023/02/03
* @params db 数据库,storeName 表名称,version 版本号
* @return { promise }
*/
const updateDB = (db, storeName, data, version = initVersion) => {
let request = db.transaction([storeName], 'readwrite') // 事务对象
.objectStore(storeName) // 仓库对象
.put(data)
return new Promise((resolve, reject) => {
request.onsuccess = function(ev) {
resolve(ev)
}
request.onerror = function(ev) {
resolve(ev)
}
})
}
/**
* 删除数据
* @author Jerome.luo
* @date 2023/02/03
* @params db 数据库,storeName 表名称,version 版本号
* @return { promise }
*/
const deleteDB = (db, storeName, key, version = initVersion) => {
let request = db.transaction([storeName], 'readwrite').objectStore(storeName).delete(key)
return new Promise((resolve, reject) => {
request.onsuccess = function(ev) {
resolve(ev)
}
request.onerror = function(ev) {
resolve(ev)
}
})
}
/**
* 删除数据库
* @author Jerome.luo
* @date 2023/02/03
* @params dbName 数据库名称
* @return { promise }
*/
const deleteDBAll = (dbName) => {
let deleteRequest = window.indexedDB.deleteDatabase(dbName)
return new Promise((resolve, reject) => {
deleteRequest.onerror = function(event) {
console.log('删除失败')
}
deleteRequest.onsuccess = function(event) {
console.log('删除成功')
}
})
}
/**
* 关闭数据库
* @author Jerome.luo
* @date 2023/02/03
* @params db 数据库
* @return { promise }
*/
const closeDB = (db) => {
db.close()
console.log('数据库已关闭')
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
后期根据业务需要,不断添加与完善。
# 前端脚手架(npm库) eci-cli
# 背景简介
前端有很多优秀的脚手架资源例如Vue-cli,create-react-app等,这些脚手架提供了简单的基本配置,以及部分定制化的内容,根据用户的选择去整合相关开发资源依赖,兼容处理,工程化配置,以及完整的环境配置,基本提供了完整的功能;
这些主流的脚手架也具有一定局限性,没法根据公司自己的技术盏选型去做深度定制化内容开发,官方出于满足大众化的需求提供的项目模板过于简单,而企业级教手架则需要在上层进行二次封装或者完善才能满足真正的项目需求。所以我们结合主流脚手架的搭建方案开发我们内部定制化的脚手架eci-cli;
关于eci-cli, 采用Vue3 + vite + element-plus 等工程的自动化构建,支持Vuex状态管理库,aixos请求等。采用vite为资源整合打包工具,需具有丰富的中文注释,能提供真正的开箱即用功能;
eci-cli 脚手架上架后,长期维护优化并升级
# eci-cli 前端框架项目构建步骤
* 需要提前安装好node环境
1.全局安装eci-cli脚手架
cnpm i eci-cli -g
或
npm i eci-cli -g
2
3
2.初始化项目,输入命令
eci-cli init
或
eci init
2
3
3.按提示输入或根据需要选择(项目名,项目描述,版本号,项目类型web & mob)
4.项目下载完成
cd 项目名 // 切换到项目下
npm install // 安装依赖(后续安装依赖集成到脚手架中,可省略此命令,直接运行项目了)
npm run dev // 依赖安装完成,运行项目
2
3
# 项目实战
# 可配置查询 demo
1.支持筛选条件显示隐藏,排序,name修改的控制
2.支持查询结果字段显示隐藏,字段显示排序,name修改,数据排序,字段是否允许勾选导出,导出模板设置的控制
3.支持表单(表头,表体)控件只读,必填,label修改,默认值的控制
2
3
- 代码文件夹copy
- 文件夹结构与命名规范:业务代码mati,detl 详情组件,hooks 业务js代码,mitn 编辑组件,sech 查询组件
# 1.查询条件
- 代码结构, <筛选配置,筛选控件,筛选配置弹窗,js,css>
- 编写自己需要的筛选条件控件
- 输入框、下拉框、日期、放大镜控件使用
- 配置entity.queryField筛选条件拼接参数:
data-query="a.platNo|l"
1 - 筛选配置组件传入业务类型 bizType
- 配置默认排序数组 defaultSort
- 筛选条件useFormFilter.js 传入业务类型
代码结构
控件类型
# 2.查询结果
- 代码结构, <筛选组件,按钮,查询表格,分页,表格配置弹窗,js,css>
- 表格内容,有特殊显示要求,单独写
- 表格配置组件传入业务类型 bizType
- 配置默认排序数组 defaultSort
- 查询结果useFormSech.js 传入业务类型
- 配置查询api接口,例如:
initCfg.searchSource = '$$api_mat_selectPageList'
1
# 3.表单(表头表体)
- 代码结构,<按钮区域,表单form,其他业务功能组件,js,css>
- 编写表单form的控件内容,UI组件同筛选条件
- 绑定字段,==v-model="formParams.copGNo"==
- 设置控件label,$t 国际化
:label="$t('gw_material_list_cop_g_no')"
1 - 绑定控件配置功能,传入字段和参数(固定),自定义指令
v-formConfig="{ column: 'copGNo', ...headFormData }"
1 - 绑定控件回车键跳转下一步函数(固定写法)
:ref="enterRef" @keyup.native.enter="$Tools.focusNext($event, enterRefArr)"
1
2 - 表头表单useFormHeader.js 传入业务类型
- entity = {} 罗列表单所有字段,数据初始化和数据回填