Ffast-FE: быстрое решение для разработки на основе Vue и IView
Установка:
# install dependencies
npm install or yarn
# serve with hot reload at localhost:8000
npm run dev
# build for production with minification
npm run build
Введение: Ffast-FE — это быстрое решение для разработки, основанное на Vue и IView. Оно позволяет использовать JSON-данные для управления страницами и создавать собственные страницы с помощью нескольких строк кода.
Демонстрационные адреса:
Технологический стек: Vue2 + Vuex + Vue-Router + Webpack + ES6 + Axios + IView
Структура каталога:
.
├── build проект сборки конфигурации
├── config конфигурация разработки
├── static статические ресурсы для сборки
└── src
├── main.js конфигурации входа
├── routes.js настройки маршрутизации
├── config.js API-интерфейсы проекта конфигурации
├── locale.js многоязычная конфигурация
├── components компоненты
├── config настройка проекта
├── directive пользовательские директивы
├── pages бизнес-страницы
├── styles глобальные стили
├── mock mock-данные
├── vuex конфигурация Vuex
├── view файлы страниц
└── utils классы инструментов
Ffast-Java: решение для бэкенда
Реализованные модули:
Модули в разработке:
Эффектные изображения:
Изображение | Описание |
---|---|
page1.jpg | Страница 1 |
page2.jpg | Страница 2 |
page3.jpg | Страница 3 |
page4.jpg | Страница 4 |
page5.jpg | Страница 5 |
page6.jpg | Страница 6 |
page7.jpg | Страница 7 |
page8.jpg | Страница 8 |
page9.jpg | Страница 9 |
page10.jpg | Страница 10 |
Пример страницы CRUDView:
<template>
<CrudView :tableOptions="tableOptions" ></CrudView>
</template>
<script>
/**
* Параметры всплывающей формы
*/
const tableEditOptions = {
// Разрешить переход на страницу редактирования, если пусто или false, используйте всплывающее окно для редактирования
editPage: true,
// Ширина модального окна
width: 600,
// Метка ширины формы
labelWidth: 70,
// Динамические данные формы
dynamic: [
[
{name: 'id', hidden: true},
{
name: 'name',
type: 'text',
span: 12,
label: 'Имя ресурса',
rules: {required: true}
},
{name: 'parentId', type: 'treeSelect', dataFromTree: true, span: 12, label: 'Родительский ресурс'}
],
[
{name: 'url', type: 'text', span: 24, label: 'URL меню'}
],
[
{name: 'identity', type: 'text', span: 12, label: 'Идентификатор'},
{name: 'icon', type: 'text', span: 12, label: 'Значок'}
],
[
{
name: 'status',
openText: 'Показать',
closeText: 'Скрыть',
type: 'switch',
span: 12,
label: 'Статус',
value: 1,
trueValue: 1,
falseValue: 0
},
{
name: 'resType',
type: 'radio',
span: 12,
label: 'Тип',
value: 1,
data: [{label: 'Меню', value: 1}, {label: 'Разрешение', value: 2}],
rules: {required: true, type: 'number'}
}
],
[
{
name: 'addBaseCrud',
type: 'switch',
openText: 'Да',
closeText: 'Нет',
span: 12,
label: 'Добавить базовое разрешение',
value: false
}
]
]
}
/**
* Параметры таблицы
*/
const tableOptions = {
editOptions: tableEditOptions,
selection: [],
pageSize: 20,
// Заголовок окна формы
title: 'Разрешения меню',
// Префикс разрешения
permsPrefix: 'res',
// Адрес данных таблицы
dataUrl: '/sys/res/list',
// URL создания данных таблицы
createUrl: '/sys/res/create',
// URL удаления данных таблицы
deleteUrl: '/sys/res/delete',
// URL обновления данных таблицы
updateUrl: '/sys/res/update',
// Запрос параметров запроса
param: {},
// Столбцы данных таблицы
columns: [
{type: 'selection', width: 60, align: 'center'},
{key: 'name', title: 'Имя ресурса', minWidth: 160, maxWidth: 280},
{
key: 'resType',
width: 80,
title: 'Тип',
// Тип перечисления (автоматическое преобразование значения (id) в соответствующую метку value)
enum: [{value: 'Меню', id: 1, el: 'strong'}, {value: 'Разрешение', id: 2}]
},
{key: 'identity', title: 'Идентификатор', ...}
``` ```
width: 200},
{key: 'url', title: '菜单Url', minWidth: 200, maxWidth: 400},
{key: 'parentId', title: '父资源', width: 160, dataFromTree: true},
{
key: 'icon',
width: 100,
title: '菜单图标',
render: (h, params) => {
const row = params.row
return h('Icon', {
props: {
type: row.icon
}
})
}
},
{key: 'weight', title: '权重', width: 80},
{
key: 'status',
width: 80,
title: '状态',
enum: ['隐藏', '显示']
}
],
// 表格搜索表单
searchDynamic: [
[
{name: 'name', label: '资源名', span: 4, type: 'text'},
{
name: 'resType',
type: 'select',
data: [{label: '菜单', value: 1}, {label: '权限', value: 2}],
span: 3,
label: '类型'
}
]
]
Гибкий и богатый динамический компонент формы (FormDynamic)
<template>
<div class="main-view main-view-full" style="padding-top: 50px">
<row>
<i-col span="24">
<FormDynamic ref="dynamic1" v-model="fromData" :data="dynamic1" :label-width="120">
</FormDynamic>
</i-col>
</row>
<PopupEdit ref="popupEdit"
:width="1000"
:dynamic="dynamic1"
@on-success="editSuccess"
:label-width="120">
</PopupEdit>
<PopupSelect ref="popSelect" :content="userPage"></PopupSelect>
</div>
</template>
<script>
import {FormDynamic, PopupEdit, PopupSelect} from 'components/';
let self = null;
const dynamic1 = [
[
{type: 'title', span: 24, text: 'Input'}
],
[
{
name: 'numberData',
type: 'number',
span: 6,
// минимальное значение
min:1,
// максимальное значение
max:80010
label: 'Number'
},
{
name: 'textData',
type: 'text',
span: 6,
label: 'text',
value: 'DefaultValue',
rules: {required: true, type: 'string'}
},
{
name: 'passwordData',
type: 'text',
span: 6,
password: true,
label: 'PasswordText',
rules: {required: true, type: 'string', message: '密码不能为空'}
},
{
name: 'textarea',
type: 'text',
placeholder: '多行文本输入框',
span: 6,
label: 'TextareaLabel',
textarea: {minRows: 1, maxRows: 6}
}
], [
{type: 'title', span: 24, text: 'date'}
], [
{name: 'date1', type: 'date', span: 6, label: 'DateLabel'},
{name: 'date2', type: 'datetime', span: 6, label: 'DateTimeLabel'},
{name: 'date3', type: 'datetimerange', span: 6, label: 'Datetimerange'}
],
[
{type: 'title', span: 24, text: 'DataSelect'}
],
[
{
name: 'selectData',
type: 'select',
span: 8,
value: 0,
label: 'SelectLabel',
data: [
{label: '选项1', value: 0}, {label: '选项2', value: 1},
{label: '选项3', value: 2}, {label: '选项4', value: 3}
],
onChange: (val, from, data) => {
alert('onChange');
}
},
{
name: 'selectData2',
type: 'select',
span: 6,
value: 0,
label: 'URLSelectLabel',
// значение поля имени
valField: 'id',
// метка поля имени
textField: 'name',
// получение данных через URL
dataUrl: '/sys/dict/get?type=job',
``` onChange: (val, from, data) => {
alert('onChange');
},
{
name: 'selectData3',
type: 'select',
span: 6,
value: 0,
label: 'DictSelectLabel',
// 直接取字典数据
dict: 'job',
onChange: (val, from, data) => {
alert('onChange');
}
},
{
name: 'radioData',
type: 'radio',
span: 6,
value: 0,
label: 'RadioLabel',
data: [
{label: '选项1', value: 0}, {label: '选项2', value: 1},
{label: '选项3', value: 2}, {label: '选项4', value: 3}
],
onChange: (val, from, data) => {
alert('onChange');
}
},
{
name: 'checkboxData',
type: 'checkbox',
span: 8,
label: 'CheckboxLabel',
data: [
{label: '选项1', value: 0}, {label: '选项2', value: 1},
{label: '选项3', value: 2}, {label: '选项4', value: 3}
],
enableCheckAll: true,
checkAllLabel: '全选',
checkAll: true,
onChange: (val, from, data) => {
alert('onChange');
}
},
{
name: 'deviceTypeId',
type: 'treeSelect',
span: 8,
label: 'TreeSelectLabel',
// 如果是CrudView 支持从左边树绑定数据,select组件同样支持
dataFromTree: true,
textField: 'name',
valField: 'id',
dataUrl: '/sys/res/list',
onChange: (val, from, data) => {
alert('onChange');
}
},
{
name: 'popSelectId',
span:
8,
label:
'PopupSelectLabel',
type:
'popText',
textField:
'popSelectName',
onClick(fromData) {
self.$refs['popSelect'].open((selection) => {
console.log(selection[0].id);
self.$set(fromData, 'popSelectId', selection[0].id);
self.$set(fromData, 'popSelectName', selection[0].username);
})
}
},
{
name: 'imgData',
// 最多只能上传2张
max: 2,
type: 'imgUpload',
span: 24,
label: 'ImgUploadLabel'
},
{name: 'editor', type: 'editor', span: 24, label: 'EditorLabel', placeholder: '富文本编辑器'},
{
name: 'button', type: 'buttons',
span: 24,
data: [
{
label: 'SetData',
onClick() {
// 给表单设置数据
self.$refs.dynamic1.setFormData({numberData: 10001, textData: 'SetData'})
}
},
{
label: 'GetFormData',
onClick() {
self.$refs.dynamic1.submit((param) => {
console.log(param);
alert(JSON.stringify(param))
}, (res) => {
// 表单验证失败
});
}
},
{
// 弹出窗口编辑表单
label: 'PopupWindow',
onClick() {
self.$refs.popupEdit.open({
title: 'PopupEditWindow',
// 确认提交url
postUrl: null
}, self.fromData);
}
},
{
label: 'GotoEditPage',
onClick() {
self.editOptions.editSuccess = self.editSuccess;
let action = {
// 窗口标题
title: 'title',
// 确认提交请求url
postUrl: ''
}
self.$router.push({
path: self.$router.currentRoute.path + '/edit',
query: {options: self.editOptions, action: action, data: self.fromData}
})
}
}
]
} **editOptions = {**
width: 1200,
labelWidth: 120,
dynamic: dynamic1
};
export default {
data() {
return {
editOptions,
dynamic1,
fromData: {}
}
},
computed: {
// 弹出选择页面
userPage() {
return import('pages/sys/user');
}
},
methods: {
// 编辑成功
editSuccess(res) {
console.log(res);
}
},
mounted() {
self = this;
},
components: {
FormDynamic, PopupEdit, PopupSelect
}
}
</script>
## 排版规则
[ [{}...],//第一行 [], //第二行 [], //第三行 ] 也可以设置为span:24 独占一行
## 表单验证
rules: { required: true, //开启表单验证 type: 'number', //验证类型 message: '分类不能为空'//提示信息 } 具体请看https://github.com/yiminghe/async-validator
## Вы можете использовать и другие компоненты, разработанные на основе динамических форм
* Всплывающая форма редактирования (PopupEdit)
* Форма редактирования перехода (edit.vue)
## Что ещё?
* CrudTreeView (древовидная структура редактирования)
* PhotoViewer (компонент для просмотра изображений)
* DataTree (дерево данных)
* DataSelect (компоненты для выбора данных, включая возможность прямого ввода идентификатора словаря)
* DataTable (таблица данных)
* CrudTree (CRUD дерево)
* CrudTable (CRUD таблица)
* PermsValid (проверка прав доступа)
...
## Ссылки
CrudView -> CrudTable -> DataTable -> IView Table -> PopupEdit -> FormDynamic -> Edit -> FormDynamic
-> CrudTree -> DataTree -> IView Tree
-> PopupEdit -> FormDynamic
-> Edit -> FormDynamic
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )