diff --git a/package.json b/package.json index 4878c422..512f728d 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,10 @@ "vue-router": "^3.1.3", "vue-splitpane": "^1.0.6", "vue-ueditor-wrap": "^2.4.1", - "vuex": "^3.1.2" + "vuex": "^3.1.2", + "d2-crud-plus": "^1.16.0", + "d2-crud-x": "^2.10.0", + "d2p-extends": "^1.9.9" }, "devDependencies": { "@d2-projects/vue-filename-injector": "^1.1.0", diff --git a/src/assets/svg-icons/icons/d2-crud-plus.svg b/src/assets/svg-icons/icons/d2-crud-plus.svg new file mode 100644 index 00000000..b0be458a --- /dev/null +++ b/src/assets/svg-icons/icons/d2-crud-plus.svg @@ -0,0 +1,58 @@ + + + + diff --git a/src/menu/index.js b/src/menu/index.js index e57108c6..6a54c2c2 100644 --- a/src/menu/index.js +++ b/src/menu/index.js @@ -12,6 +12,8 @@ import demoPlayground from './modules/demo-playground' import demoBusiness from './modules/demo-business' // CRUD import demoD2Crud from './modules/demo-d2-crud' +// CRUD PLUS +import demoD2CrudPlus from './modules/demo-d2-crud-plus' // 第三方网页 import demoFrame from './modules/demo-frame' @@ -38,6 +40,7 @@ export const menuAside = supplementPath([ demoPlayground, demoBusiness, demoD2Crud, + demoD2CrudPlus, demoFrame ]) @@ -53,6 +56,7 @@ export const menuHeader = supplementPath([ icon: 'puzzle-piece', children: [ demoD2Crud, + demoD2CrudPlus, demoComponents, demoCharts, demoPlugins, diff --git a/src/menu/modules/demo-d2-crud-plus.js b/src/menu/modules/demo-d2-crud-plus.js new file mode 100644 index 00000000..f5ae86cc --- /dev/null +++ b/src/menu/modules/demo-d2-crud-plus.js @@ -0,0 +1,32 @@ +import '@/views/demo/d2-crud-plus/install' +export default { + path: '/demo/d2-crud-plus', + title: 'D2 CRUD PLUS', + iconSvg: 'd2-crud-plus', + children: (pre => [ + { path: `${pre}index`, title: 'D2 CRUD PLUS', icon: 'home' }, + { + title: '简单示例', + path: `${pre}demo` + }, + { + title: '表单分组', + path: `${pre}group` + }, + { + title: '综合示例', + path: `${pre}synthesize` + }, + { + title: '更多示例', + icon: 'link', + path: 'http://qiniu.veryreader.com/D2CrudPlusExample/' + }, + { + title: '帮助文档', + icon: 'link', + path: 'http://greper.gitee.io/d2-crud-plus/' + } + + ])('/demo/d2-crud-plus/') +} diff --git a/src/router/modules/d2-crud-plus.js b/src/router/modules/d2-crud-plus.js new file mode 100644 index 00000000..c1f9ac0c --- /dev/null +++ b/src/router/modules/d2-crud-plus.js @@ -0,0 +1,21 @@ +import layoutHeaderAside from '@/layout/header-aside' + +// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载 +const _import = require('@/libs/util.import.' + process.env.NODE_ENV) + +const meta = { auth: true } + +export default { + path: '/demo/d2-crud-plus', + name: 'demo-d2-crud-plus', + meta, + redirect: { name: 'demo-d2-crud-plus-index' }, + component: layoutHeaderAside, + children: (pre => [ + { path: 'index', name: `${pre}index`, component: _import('demo/d2-crud-plus/index'), meta: { ...meta, title: 'D2 CRUD PLUS 首页' } }, + { path: 'demo', name: `${pre}demo`, component: _import('demo/d2-crud-plus/demo'), meta: { ...meta, title: '简单示例' } }, + { path: 'group', name: `${pre}group`, component: _import('demo/d2-crud-plus/group'), meta: { ...meta, title: '表单分组' } }, + { path: 'synthesize', name: `${pre}synthesize`, component: _import('demo/d2-crud-plus/synthesize'), meta: { ...meta, title: '综合示例' } } + + ])('demo-d2-crud-plus-') +} diff --git a/src/router/routes.js b/src/router/routes.js index 9e57ad35..f1cbd87f 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -1,6 +1,7 @@ import playground from './modules/playground' import frame from './modules/frame' import d2Crud from './modules/d2-crud' +import d2CrudPlus from './modules/d2-crud-plus' import plugins from './modules/plugins' import charts from './modules/charts' import components from './modules/components' @@ -59,6 +60,7 @@ const frameIn = [ playground, frame, d2Crud, + d2CrudPlus, plugins, charts, components, diff --git a/src/views/demo/d2-crud-plus/demo/api.js b/src/views/demo/d2-crud-plus/demo/api.js new file mode 100644 index 00000000..2007f17d --- /dev/null +++ b/src/views/demo/d2-crud-plus/demo/api.js @@ -0,0 +1,36 @@ +// 请求真实后端 +// import { request } from '@/api/service' + +// 请求模拟数据 +import { requestForMock } from '@/api/service' + +export function GetList (query) { + return requestForMock({ + url: '/d2crudplus/test/page', + method: 'get', + data: query + }) +} + +export function AddObj (obj) { + return requestForMock({ + url: '/d2crudplus/test/add', + method: 'post', + data: obj + }) +} + +export function UpdateObj (obj) { + return requestForMock({ + url: '/d2crudplus/test/update', + method: 'post', + data: obj + }) +} +export function DelObj (id) { + return requestForMock({ + url: '/d2crudplus/test/delete', + method: 'post', + data: { id } + }) +} diff --git a/src/views/demo/d2-crud-plus/demo/crud.js b/src/views/demo/d2-crud-plus/demo/crud.js new file mode 100644 index 00000000..28db5fec --- /dev/null +++ b/src/views/demo/d2-crud-plus/demo/crud.js @@ -0,0 +1,51 @@ +export const crudOptions = (vm) => { + return { + viewOptions: { + componentType: 'row' // 查看对话框字段使用行组件 + }, + columns: [ + { + title: 'ID', + key: 'id', + width: 90, + form: { + disabled: true + } + }, + { + title: '日期', + key: 'date', + type: 'date' + }, + { + title: '状态', + key: 'status', + sortable: true, + search: { disabled: false }, + type: 'select', + dict: { + url: '/d2crudplus/dicts/OpenStatusEnum' + } + }, + { + title: '地区', + key: 'address', + sortable: true, + width: 180, + search: { disabled: false }, + type: 'select', + form: { + component: { + props: { + multiple: true // 多选 + } + } + }, + dict: { + data: [{ value: 'sz', label: '深圳' }, { value: 'gz', label: '广州' }, { value: 'wh', label: '武汉' }, { value: 'sh', label: '上海' }] + }, + component: { props: { color: 'auto' } } // 自动染色 + } + ] + } +} diff --git a/src/views/demo/d2-crud-plus/demo/index.vue b/src/views/demo/d2-crud-plus/demo/index.vue new file mode 100644 index 00000000..8e045446 --- /dev/null +++ b/src/views/demo/d2-crud-plus/demo/index.vue @@ -0,0 +1,57 @@ + + + 简单示例 + + + + + + + 新增 + + + + + + + + + + diff --git a/src/views/demo/d2-crud-plus/demo/mock.js b/src/views/demo/d2-crud-plus/demo/mock.js new file mode 100644 index 00000000..784266be --- /dev/null +++ b/src/views/demo/d2-crud-plus/demo/mock.js @@ -0,0 +1,49 @@ +import mockUtil from '../mock/base' +const options = { + name: 'd2crudplus/test', + idGenerator: 0 +} +const list = [ + { + date: '2016-05-02', + status: '0', + address: 'sz' + }, + { + date: '2016-05-04', + status: '1', + address: 'sh,sz' + }, + { + date: 2232433534511, + status: '1', + address: 'gz' + }, + { + date: '2016-05-03', + status: '2', + address: 'wh,gz' + } +] +const openStatus = [ + { value: '1', label: '打开', color: 'success' }, + { value: '2', label: '停止', color: 'info' }, + { value: '0', label: '关闭', color: 'danger' } +] + +options.list = list +const mock = mockUtil.buildMock(options) +mock.push( + { + path: '/d2crudplus/dicts/OpenStatusEnum', + method: 'get', + handle ({ body }) { + return { + code: 0, + msg: 'success', + data: openStatus + } + } + } +) +export default mock diff --git a/src/views/demo/d2-crud-plus/group/api.js b/src/views/demo/d2-crud-plus/group/api.js new file mode 100644 index 00000000..6229116b --- /dev/null +++ b/src/views/demo/d2-crud-plus/group/api.js @@ -0,0 +1,36 @@ +// 请求真实后端 +// import { request } from '@/api/service' + +// 请求模拟数据 +import { requestForMock } from '@/api/service' + +export function GetList (query) { + return requestForMock({ + url: '/d2crudplus/group/page', + method: 'get', + data: query + }) +} + +export function AddObj (obj) { + return requestForMock({ + url: '/d2crudplus/group/add', + method: 'post', + data: obj + }) +} + +export function UpdateObj (obj) { + return requestForMock({ + url: '/d2crudplus/group/update', + method: 'post', + data: obj + }) +} +export function DelObj (id) { + return requestForMock({ + url: '/d2crudplus/group/delete', + method: 'post', + data: { id } + }) +} diff --git a/src/views/demo/d2-crud-plus/group/crud.js b/src/views/demo/d2-crud-plus/group/crud.js new file mode 100644 index 00000000..d917fb83 --- /dev/null +++ b/src/views/demo/d2-crud-plus/group/crud.js @@ -0,0 +1,125 @@ +export const crudOptions = { + options: { + height: '100%' // 表格高度100%, 使用toolbar必须设置 + }, + viewOptions: { + disabled: false + }, + rowHandle: { + }, + columns: [ + { + title: 'ID', + key: 'id', + width: 90, + form: { + disabled: true + } + }, + { + title: '商品标题', + key: 'title', + sortable: true + }, + { + title: '商品代码', + key: 'code', + search: { disabled: false }, + sortable: true + }, + // { + // title: '图片', + // key: 'images', + // sortable: true, + // type: 'image-uploader', + // form: { + // component: { + // props: { + // uploader: { + // type: 'form' + // } + // } + // } + // } + // }, + { + title: '价格', + key: 'price', + sortable: true + }, + { + title: '库存', + key: 'store', + sortable: true, + type: 'number' + }, + { + title: '简介', + key: 'intro', + sortable: true, + type: 'text-area' + }, + // { + // title: '详情', + // key: 'content', + // sortable: true, + // type: 'editor-ueditor', + // disabled: true + // }, + { + title: '自定义', + key: 'custom', + sortable: true, + form: { + component: { + span: 24 + }, + slot: true + } + }, + { + title: '自定义2', + key: 'custom2', + sortable: true, + form: { + component: { + span: 24 + }, + slot: true + } + } + ], + formGroup: { + type: 'collapse', // tab + accordion: false, + groups: { + base: { + title: '商品基础', + icon: 'el-icon-goods', + columns: ['title', 'code', 'images'] + }, + price: { + title: '库存价格', + icon: 'el-icon-price-tag', + columns: ['store', 'price'] + }, + info: { + title: '详情', + collapsed: false, + icon: 'el-icon-warning-outline', + columns: ['intro', 'content'] + }, + custom: { + title: '自定义', + collapsed: true, + show (context) { + console.log('custom context', context) + return context.mode === 'view' + }, + disabled: false, + icon: 'el-icon-warning-outline', + columns: ['custom', 'custom2'] + } + } + } +} diff --git a/src/views/demo/d2-crud-plus/group/index.vue b/src/views/demo/d2-crud-plus/group/index.vue new file mode 100644 index 00000000..3540ef79 --- /dev/null +++ b/src/views/demo/d2-crud-plus/group/index.vue @@ -0,0 +1,61 @@ + + + 表单分组 + + + + + + 新增 + + + + {{scope.group.title}} + (我是自定义标题) + + + + 自定义选项 + + + + + + + + diff --git a/src/views/demo/d2-crud-plus/group/mock.js b/src/views/demo/d2-crud-plus/group/mock.js new file mode 100644 index 00000000..dcbd01ab --- /dev/null +++ b/src/views/demo/d2-crud-plus/group/mock.js @@ -0,0 +1,20 @@ +import mockUtil from '../mock/base' + +const options = { + name: 'd2crudplus/group', + idGenerator: 0 +} +const list = [ + { + title: '无线充电宝', + code: '100001', + images: 'https://img0.bdstatic.com/static/searchdetail/img/logo-2X_0c4ef02.png', + price: 100, + stock: 99, + intro: '30000毫安超大容量移动电源充电宝官方原装正品专用便携', + content: '' + } +] +options.list = list +const mock = mockUtil.buildMock(options) +export default mock diff --git a/src/views/demo/d2-crud-plus/index/helper.js b/src/views/demo/d2-crud-plus/index/helper.js new file mode 100644 index 00000000..a836beb5 --- /dev/null +++ b/src/views/demo/d2-crud-plus/index/helper.js @@ -0,0 +1,34 @@ +export default { + crud: ` columns: [ + { + title: '日期', //字段名称 + key: 'date', //字段key + type: 'date', //字段类型,添加、修改、查询将自动生成相应表单组件 + }, + { + title: '状态', + key: 'status', + type: 'select', //选择框,默认单选 + dict: { url: '/dicts/OpenStatusEnum' }//远程数据字典 + }, + { + title: '地区', + key: 'address', + type: 'select', //选择框 + form: { //表单组件自定义配置 + component: { //支持任何v-model组件 + props: { multiple: true } // 此处配置选择框为多选 + } + }, + dict: { + data: [ //本地数据字典 + { value: 'sz', label: '深圳' }, + { value: 'gz', label: '广州' }, + { value: 'wh', label: '武汉' }, + { value: 'sh', label: '上海' } + ] + } + } + ] + ` +} diff --git a/src/views/demo/d2-crud-plus/index/image/gif.webp b/src/views/demo/d2-crud-plus/index/image/gif.webp new file mode 100644 index 00000000..f61b760a Binary files /dev/null and b/src/views/demo/d2-crud-plus/index/image/gif.webp differ diff --git a/src/views/demo/d2-crud-plus/index/index.vue b/src/views/demo/d2-crud-plus/index/index.vue new file mode 100644 index 00000000..42b7c55b --- /dev/null +++ b/src/views/demo/d2-crud-plus/index/index.vue @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/views/demo/d2-crud-plus/install.js b/src/views/demo/d2-crud-plus/install.js new file mode 100644 index 00000000..77010f6f --- /dev/null +++ b/src/views/demo/d2-crud-plus/install.js @@ -0,0 +1,87 @@ +import Vue from 'vue' +import d2CrudX from 'd2-crud-x' +import { d2CrudPlus } from 'd2-crud-plus' +import { D2pAreaSelector, D2pFileUploader, D2pIconSelector, D2pTreeSelector, D2pFullEditor, D2pUploader, D2pDemoExtend } from 'd2p-extends' // 源码方式引入,上传组件支持懒加载 +// http请求 +import { requestForMock } from '@/api/service' +import './mock' // 模拟数据 + +// 按如下重命名引入可与官方版共存,index.vue中标签用使用加强版 +// 不传name,则d2CrudX的标签仍为,不可与官方版共存 +Vue.use(d2CrudX, { name: 'd2-crud-x' }) + +// 引入d2CrudPlus +Vue.use(d2CrudPlus, { + starTip: false, + getRemoteDictFunc (url, dict) { + // 此处配置你的字典http请求方法 + // 实际使用请改成request + return requestForMock({ + url: url, + data: dict.body, + method: 'get' + }) + }, + commonOption () { // 公共配置 + return { + format: { + response (res) { + return res + }, + page: { // page接口返回的数据结构配置, + request: { + current: 'current', + size: 'size' + }, + response: { + current: 'current', // 当前页码 ret.data.current + size: 'size', // 当前页码 ret.data.current + // size: (data) => { return data.size }, // 每页条数,ret.data.size, 你也可以配置一个方法,自定义返回 + total: 'total', // 总记录数 ret.data.total + records: 'records' // 列表数组 ret.data.records + } + } + }, + pageOptions: { + compact: true // 紧凑型页面模式 + }, + options: { + size: 'small', + height: '100%' // 表格高度100% + }, + formOptions: { + nullToBlankStr: true, // 提交修改表单时,将undefinded的数据修改为空字符串'',可以解决无法清空字段的问题 + defaultSpan: 12 // 默认的表单 span + }, + viewOptions: { + disabled: false, + componentType: 'form' // 【form,row】 表单组件 或 行组件展示 + }, + rowHandle: { + width: 260, + edit: { + type: 'primary' + } + } + } + } +}) + +// 安装扩展插件 +Vue.use(D2pTreeSelector) +Vue.use(D2pAreaSelector) +Vue.use(D2pIconSelector) +Vue.use(D2pFullEditor, { + ueditor: { + serverUrl: '/api/ueditor/' + } +}) +Vue.use(D2pDemoExtend) +Vue.use(D2pFileUploader) +Vue.use(D2pUploader, { + defaultType: 'form', + form: { + action: 'http://qiniu.veryreader.com/D2CrudPlusExample/upload/form/upload', + name: 'file' + } +}) diff --git a/src/views/demo/d2-crud-plus/mock/base.js b/src/views/demo/d2-crud-plus/mock/base.js new file mode 100644 index 00000000..3327bc1e --- /dev/null +++ b/src/views/demo/d2-crud-plus/mock/base.js @@ -0,0 +1,234 @@ +function copyList (originList, newList, options, parentId) { + for (const item of originList) { + const newItem = { ...item, parentId } + newItem.id = ++options.idGenerator + newList.push(newItem) + if (item.children != null) { + newItem.children = [] + copyList(item.children, newItem.children, options, newItem.id) + } + } +} + +function delById (req, list) { + for (let i = 0; i < list.length; i++) { + const item = list[i] + if ((item.id) === parseInt(req.params.id)) { + console.log('remove i') + list.splice(i, 1) + break + } + if (item.children != null && item.children.length > 0) { + delById(req, item.children) + } + } +} +export default { + findById (id, list) { + for (const item of list) { + if (item.id === id) { + return item + } + if (item.children != null && item.children.length > 0) { + const sub = this.findById(id, item.children) + if (sub != null) { + return sub + } + } + } + }, + buildMock (options) { + const name = options.name + if (options.copyTimes == null) { + options.copyTimes = 29 + } + const list = [] + for (let i = 0; i < options.copyTimes; i++) { + copyList(options.list, list, options) + } + options.list = list + return [ + { + path: '/' + name + '/page', + method: 'get', + handle (req) { + let data = list + let size = 20 + let current = 1 + for (const item of list) { + if (item.children != null && item.children.length === 0) { + item.hasChildren = false + item.lazy = false + } + } + if (req != null && req.body != null) { + if (req.body.size != null) { + size = parseInt(req.body.size) + } + if (req.body.current != null) { + current = parseInt(req.body.current) + } + const query = { ...req.body } + delete query.current + delete query.size + if (Object.keys(query).length > 0) { + data = list.filter(item => { + let allFound = true // 是否所有条件都符合 + for (const key in query) { + // 判定某一个条件 + const value = query[key] + if (value == null || value === '') { + continue + } + if (value instanceof Array) { + // 如果条件中的value是数组的话,只要查到一个就行 + if (value.length === 0) { + continue + } + let found = false + for (const i of value) { + if (item[key] instanceof Array) { + for (const j of item[key]) { + if (i === j) { + found = true + break + } + } + if (found) { + break + } + } else if (item[key] === i || ((typeof item[key]) === 'string' && item[key].indexOf(i + '') >= 0)) { + found = true + break + } + if (found) { + break + } + } + if (!found) { + allFound = false + } + } else if (value instanceof Object) { + for (const key2 in value) { + const v = value[key2] + if (v && v !== item[key][key2]) { + return false + } + } + } else if (item[key] !== value) { + allFound = false + } + } + return allFound + }) + } + } + + const start = size * (current - 1) + let end = size * current + if (data.length < end) { + end = data.length + } + const records = data.slice(start, end) + const maxPage = data.length % size === 0 ? data.length / size : Math.floor(data.length / size) + 1 + if (current > maxPage) { + current = maxPage + } + if (current < 1) { + current = 1 + } + return { + code: 0, + msg: 'success', + data: { + records: records, + total: data.length, + size: size, + current: current + } + } + } + }, + { + path: '/' + name + '/get', + method: 'get', + handle (req) { + let id = req.params.id + id = parseInt(id) + let current = null + for (const item of list) { + if (item.id === id) { + current = item + break + } + } + return { + code: 0, + msg: 'success', + data: current + } + } + }, + { + path: '/' + name + '/add', + method: 'post', + handle (req) { + req.body.id = ++options.idGenerator + list.unshift(req.body) + return { + code: 0, + msg: 'success', + data: null + } + } + }, + { + path: '/' + name + '/update', + method: 'post', + handle (req) { + for (const item of list) { + if (item.id === req.body.id) { + Object.assign(item, req.body) + break + } + } + return { + code: 0, + msg: 'success', + data: null + } + } + }, + { + path: '/' + name + '/delete', + method: 'post', + handle (req) { + delById(req, list) + return { + code: 0, + msg: 'success', + data: null + } + } + }, + { + path: '/' + name + '/batchDelete', + method: 'post', + handle (req) { + const ids = req.body.ids + for (let i = list.length - 1; i >= 0; i--) { + const item = list[i] + if (ids.indexOf(item.id) >= 0) { + list.splice(i, 1) + } + } + return { + code: 0, + msg: 'success', + data: null + } + } + } + ] + } +} diff --git a/src/views/demo/d2-crud-plus/mock/index.js b/src/views/demo/d2-crud-plus/mock/index.js new file mode 100644 index 00000000..73315e7e --- /dev/null +++ b/src/views/demo/d2-crud-plus/mock/index.js @@ -0,0 +1,44 @@ +import { mock } from '@/api/service' +import * as tools from '@/api/tools' + +const req = context => context.keys().map(context) + +// 模拟数据 +const apiList = req(require.context('../', true, /mock\.js$/)) + .filter(e => e.default) + .map(e => e.default) + +apiList.forEach(apiFile => { + for (const item of apiFile) { + mock + .onAny(new RegExp('^' + item.path)) + .reply(config => { + console.log('------------fake request start -------------') + console.log('request:', config) + const data = config.data ? JSON.parse(config.data) : {} + const query = config.url.indexOf('?') >= 0 ? config.url.substring(config.url.indexOf('?') + 1) : undefined + let params = {} + if (query) { + const arr = query.split('&') + for (const item of arr) { + const kv = item.split('=') + params[kv[0]] = kv[1] + } + } else { + params = data + } + const req = { + body: data, + params: params + } + const ret = item.handle(req) + console.log('response:', ret) + console.log('------------fake request end-------------') + if (ret.code === 0) { + return tools.responseSuccess(ret.data, ret.msg) + } else { + return tools.responseError(ret.data, ret.msg, ret.code) + } + }) + } +}) diff --git a/src/views/demo/d2-crud-plus/synthesize/api.js b/src/views/demo/d2-crud-plus/synthesize/api.js new file mode 100644 index 00000000..4719ae98 --- /dev/null +++ b/src/views/demo/d2-crud-plus/synthesize/api.js @@ -0,0 +1,40 @@ +// 请求模拟数据 +import { requestForMock } from '@/api/service' + +export function GetList (query) { + return requestForMock({ + url: '/d2-crud-plus/synthesize/page', + method: 'get', + data: query + }) +} + +export function AddObj (obj) { + return requestForMock({ + url: '/d2-crud-plus/synthesize/add', + method: 'post', + data: obj + }) +} + +export function UpdateObj (obj) { + return requestForMock({ + url: '/d2-crud-plus/synthesize/update', + method: 'post', + data: obj + }) +} +export function DelObj (id) { + return requestForMock({ + url: '/d2-crud-plus/synthesize/delete', + method: 'post', + data: { id } + }) +} +export function BatchDel (ids) { + return requestForMock({ + url: '/d2-crud-plus/synthesize/batchDelete', + method: 'post', + data: { ids } + }) +} diff --git a/src/views/demo/d2-crud-plus/synthesize/crud.js b/src/views/demo/d2-crud-plus/synthesize/crud.js new file mode 100644 index 00000000..dc5adc64 --- /dev/null +++ b/src/views/demo/d2-crud-plus/synthesize/crud.js @@ -0,0 +1,129 @@ +// 请求模拟数据 +import { requestForMock } from '@/api/service' + +export const crudOptions = { + rowHandle: { + // columnHeader: '操作', + width: 370, + custom: [ + { + text: ' 自定义', + type: 'warning', + size: 'small', + emit: 'customHandleBtn', + icon: 'el-icon-s-flag' + } + ], + fixed: 'right' + }, + pageOptions: { + compact: true // 是否紧凑型页面 + }, + options: { + height: '100%', // 表格高度100%, 使用toolbar必须设置 + highlightCurrentRow: true, + rowKey: 'id', + lazy: true, + load: (tree, treeNode, resolve) => { + requestForMock({ + url: '/d2crudplus/synthesize/children', + method: 'get', + data: { id: tree.id } + }).then(ret => { + console.log('懒加载数据', ret) + resolve(ret) + }) + }, + showSummary: true, + summaryMethod (param) { + const { columns, data } = param + const sums = [] + columns.forEach((column, index) => { + if (index === 0) { + sums[index] = '总价' + return + } + console.log('111', column) + if (column.label !== '金额(元)') { + return + } + const values = data.map(item => Number(item[column.property])) + if (!values.every(value => isNaN(value))) { + sums[index] = values.reduce((prev, curr) => { + const value = Number(curr) + if (!isNaN(value)) { + return prev + curr + } else { + return prev + } + }, 0) + sums[index] += ' 元' + } else { + sums[index] = '' + } + }) + + return sums + } + }, + indexRow: { // 或者直接传true,不显示title,不居中 + title: '序号', + align: 'center' + }, + selectionRow: { + align: 'center', + width: 100 + }, + expandRow: { // 或者直接传true,不显示title,不居中 + title: '展开', + align: 'center' + }, + columns: [ + { + title: '数据列', + key: 'data', + sortable: true, + width: 200 + }, + { + title: 'ID', + key: 'id', + width: 90, + form: { + disabled: true + } + }, + { + title: '时间', + key: 'time', + type: 'datetime', + sortable: true, + width: 160 + }, + { + title: '地区', + key: 'province', + sortable: true, + search: { key: 'province', disabled: false }, + type: 'select', + form: { + component: { props: { filterable: true, multiple: true, clearable: true } } + }, + dict: { + data: [ + { value: 'sz', label: '深圳' }, + { value: 'gz', label: '广州' }, + { value: 'wh', label: '武汉' }, + { value: 'sh', label: '上海' } + ] + }, + width: 300 + }, + { + title: '金额(元)', + key: 'amount', + sortable: true, + type: 'number' + } + ] +} diff --git a/src/views/demo/d2-crud-plus/synthesize/helper.js b/src/views/demo/d2-crud-plus/synthesize/helper.js new file mode 100644 index 00000000..b5e8bb0b --- /dev/null +++ b/src/views/demo/d2-crud-plus/synthesize/helper.js @@ -0,0 +1,8 @@ +export default { + init: ` + `, + crud: ` +`, + template: ` + ` +} diff --git a/src/views/demo/d2-crud-plus/synthesize/index.vue b/src/views/demo/d2-crud-plus/synthesize/index.vue new file mode 100644 index 00000000..cd2ef9b1 --- /dev/null +++ b/src/views/demo/d2-crud-plus/synthesize/index.vue @@ -0,0 +1,104 @@ + + + 综合示例 + + + + + + + + + 新增 + + + + + + + 这里显示行展开数据:{{scope.row.data}} + + + + + + + + + + + diff --git a/src/views/demo/d2-crud-plus/synthesize/mock.js b/src/views/demo/d2-crud-plus/synthesize/mock.js new file mode 100644 index 00000000..d3461f27 --- /dev/null +++ b/src/views/demo/d2-crud-plus/synthesize/mock.js @@ -0,0 +1,101 @@ +import mockUtil from '../mock/base' + +const options = { + name: 'd2-crud-plus/synthesize', + idGenerator: 0 +} +const list = [ + { + data: '我会懒加载', + time: '2020-01-01 11:11:11', + province: 'wh', + amount: 100, + hasChildren: true, + loaded: false, + children: [ + { + data: '懒加载的子数据', + province: ['sh', 'gz'], + time: '2020-01-01 11:11:11', + amount: 100 + }, + { + data: '懒加载的子数据2', + province: ['sh', 'sz'], + time: '2020-01-01 11:11:11', + amount: 100 + } + ] + }, + { + data: 'data2', + province: 'sh', + time: '2020-01-01 11:11:11', + amount: 100, + children: [ + { + id: 999, + data: 'data1_1', + time: '2020-01-01 11:11:11', + province: ['gz', 'sz'], // 可以逗号分隔的字符串 'gz,sz' + amount: 100, + children: [ + { + id: 1000, + data: 'data1_1_1', + time: '2020-01-01 11:11:11', + province: ['sz', 'gz'], // 可以逗号分隔的字符串 'gz,sz' + amount: 100 + } + ] + }, + { + id: 888, + data: 'data1_2', + time: '2020-01-01 11:11:11', + province: 'sh', + amount: 100, + children: [ + { + id: 889, + data: 'data1_2_1', + time: '2020-01-01 11:11:11', + province: 'gz', + amount: 100 + } + ] + } + ] + }, + { + data: 'data3', + province: ['sh', 'gz'], + time: '2020-01-01 11:11:11', + amount: 100 + }, + { + data: 'data4', + province: ['sh', 'sz'], + time: '2020-01-01 11:11:11', + amount: 100 + } +] +options.list = list +const mock = mockUtil.buildMock(options) + +mock.push({ + path: '/d2crudplus/synthesize/children', + method: 'get', + handle (req) { + console.log('req', req) + const id = parseInt(req.params.id) + const item = mockUtil.findById(id, options.list) + console.log('children:', item.children) + return { + code: 0, + msg: 'success', + data: item.children + } + } +}) +export default mock diff --git a/yarn.lock b/yarn.lock index a9420057..729dbae4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2304,9 +2304,9 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-js@^1.0.2: +base64-js@^1.0.2, base64-js@^1.3.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== base@^0.11.1: @@ -2811,6 +2811,11 @@ check-types@^8.0.3: resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ== +china-division@^2.2.0: + version "2.3.1" + resolved "https://registry.npmjs.org/china-division/-/china-division-2.3.1.tgz#a49fa806af01d1852747466ad3c30bf0be988511" + integrity sha512-mOfLagVRZ+lRmbIIZ0sci0+9Sr+uGyPCp9an4Orov2KxLf3DGSB/4qyao/jy3pegW4Weppvh0yzGfs+dAPJA7A== + "chokidar@>=2.0.0 <4.0.0": version "3.4.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8" @@ -3325,7 +3330,7 @@ core-js@^2.4.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== -core-js@^3.4.3, core-js@^3.6.4: +core-js@^3.4.3, core-js@^3.6.4, core-js@^3.6.5: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== @@ -3335,6 +3340,13 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +cos-js-sdk-v5@^0.5.27: + version "0.5.27" + resolved "https://registry.npmjs.org/cos-js-sdk-v5/-/cos-js-sdk-v5-0.5.27.tgz#22759bc32b3f0c63caf3328400140f97f50fe6b3" + integrity sha512-kq5363l1TpU26AHRZTcWCibPfM5ykQ2zHsdpnP/Ax8SMuYQDNIP/BVWaA55Ks2r5JsELjqXLF516FeXQz3jEZw== + dependencies: + xmldom "^0.1.27" + cosmiconfig@^5.0.0, cosmiconfig@^5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" @@ -3389,6 +3401,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cropperjs@^1.5.6: + version "1.5.7" + resolved "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.7.tgz#b65019725bae1c6285e881fb661b2141fa57025b" + integrity sha512-sGj+G/ofKh+f6A4BtXLJwtcKJgMUsXYVUubfTo9grERiDGXncttefmue/fyQFvn8wfdyoD1KhDRYLfjkJFl0yw== + cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -3651,6 +3668,44 @@ cz-conventional-changelog@3.2.0, cz-conventional-changelog@^3.2.0: optionalDependencies: "@commitlint/load" ">6.1.1" +d2-crud-plus@^1.16.0: + version "1.16.0" + resolved "https://registry.npmjs.org/d2-crud-plus/-/d2-crud-plus-1.16.0.tgz#c9598377a3e2e26606cc6273868a1ee06fd9bec8" + integrity sha512-l0tu9In23gZSY15w4S4Lr2NqiZgndklUFUxImhAz5ymXdf7lU9AARpOJZxkvPYLeS349VDTP5JZVcI9Wmtnbew== + dependencies: + dayjs "^1.8.17" + lodash "^4.17.19" + vue "^2.6.11" + vuedraggable "^2.24.0" + +d2-crud-x@^2.10.0: + version "2.10.0" + resolved "https://registry.npmjs.org/d2-crud-x/-/d2-crud-x-2.10.0.tgz#67ea25ed265f80e63efad9fe4c87e1b5a3bda12b" + integrity sha512-ZKzKc4PZs9iG/0Gf9iafN8AfEFLZrEs1o+2CDcMdhyBXoNx9a6B3AL4Kkqwo3lQYHvHBhFssX7ZRw6Z5NKvlSw== + dependencies: + lodash.clonedeep "^4.5.0" + lodash.foreach "^4.5.0" + lodash.get "^4.4.2" + lodash.merge "^4.5.0" + lodash.set "^4.3.2" + +d2p-extends@^1.9.9: + version "1.9.9" + resolved "https://registry.npmjs.org/d2p-extends/-/d2p-extends-1.9.9.tgz#90cbae28427f39bb9431424e8bfee7fb06483946" + integrity sha512-Y8KkXmrJvYl8/hMWXiDEH0gkmM0b9j6hMn/g3FVWHzQYpOBS/Vu22X91yp6J6uBSJHE1IVhQFHBS3blQ/tgWUA== + dependencies: + base64-js "^1.3.0" + china-division "^2.2.0" + core-js "^3.6.5" + cos-js-sdk-v5 "^0.5.27" + cropperjs "^1.5.6" + lodash "^4.17.19" + object-assign "^4.1.1" + qiniu-js "^2.5.4" + quill "^1.3.7" + spark-md5 "^3.0.0" + vue "^2.6.11" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -7025,6 +7080,11 @@ lodash.memoize@4.x, lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= +lodash.merge@^4.5.0: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" @@ -7050,6 +7110,11 @@ lodash@4, lodash@4.17.15, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lod resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.17.19: + version "4.17.20" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -8873,6 +8938,11 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qiniu-js@^2.5.4: + version "2.5.5" + resolved "https://registry.npmjs.org/qiniu-js/-/qiniu-js-2.5.5.tgz#77d295f222620f9377d6148f3f757d189a1e4977" + integrity sha512-cJcdZMCfU4OJirjCzKJwPXSgrXF0INB2qtqA6ImNBe2PJFqi8kWE7rp3qr1RKH0H4OTtPOXyBC2FVSl/zM7ERg== + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -9775,6 +9845,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +spark-md5@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.1.tgz#83a0e255734f2ab4e5c466e5a2cfc9ba2aa2124d" + integrity sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig== + spdx-correct@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" @@ -10963,6 +11038,13 @@ vue@^2.5.11, vue@^2.5.16, vue@^2.5.19, vue@^2.6.11: resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5" integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ== +vuedraggable@^2.24.0: + version "2.24.1" + resolved "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.1.tgz#304abd7644dde05c1f199a227bf9e9107f56197a" + integrity sha512-G1fxO1oshx+WLdieSGl6jSJdlHOQFga1FpjuUpgXldbpKNzxpjsGn4xYNnRHVrOAqm8aG5FfpdQlh5LHesxCeA== + dependencies: + sortablejs "^1.10.1" + vuex@^3.1.2: version "3.3.0" resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.3.0.tgz#665b4630ea1347317139fcc5cb495aab3ec5e513" @@ -11319,6 +11401,11 @@ xmlchars@^2.1.1: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmldom@^0.1.27: + version "0.1.31" + resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" + integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== + xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"