diff --git a/package.json b/package.json index c819afc..a6dec78 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cool-admin-vue", - "version": "3.0.0", + "version": "3.0.2", "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", @@ -10,9 +10,9 @@ }, "dependencies": { "axios": "^0.21.1", - "cl-admin": "^1.3.3", - "cl-admin-crud": "^1.4.5", - "cl-admin-theme": "^0.0.3", + "cl-admin": "^1.3.4", + "cl-admin-crud": "^1.6.0", + "cl-admin-theme": "^0.0.4", "clipboard": "^2.0.7", "codemirror": "^5.59.4", "core-js": "^3.6.5", @@ -28,6 +28,7 @@ "uuid": "^8.3.2", "vue": "^2.6.11", "vue-codemirror": "^4.0.6", + "vue-cron": "^1.0.9", "vue-echarts": "^5.0.0-beta.0", "vue-router": "^3.2.0", "vuedraggable": "^2.24.3", diff --git a/src/cool/index.js b/src/cool/index.js index b1adf95..9f59772 100644 --- a/src/cool/index.js +++ b/src/cool/index.js @@ -4,17 +4,13 @@ import Theme from "cl-admin-theme"; export default { modules: [ "base", - "task", { name: "upload", options: { icon: "el-icon-picture", - text: "选择图片", - limitSize: 1, - rename: true + text: "选择图片" } }, - { name: "crud", value: Crud, @@ -29,6 +25,7 @@ export default { } } }, + "task", "copy", "distpicker", "demo", diff --git a/src/cool/modules/task/components/cron/base.js b/src/cool/modules/task/components/cron/base.js deleted file mode 100644 index 6f406d5..0000000 --- a/src/cool/modules/task/components/cron/base.js +++ /dev/null @@ -1,459 +0,0 @@ -/** - * 表单项基础类, 所有输入组件都继承Base - * @module $ui/components/my-form/src/Base - */ - -import { FormItem } from "element-ui"; -import { setStyle } from "element-ui/lib/utils/dom"; -import { addResizeListener, removeResizeListener } from "element-ui/lib/utils/resize-event"; - -const _get = require("lodash/get"); -const _set = require("lodash/set"); -const _isEqual = require("lodash/isEqual"); -const _cloneDeep = require("lodash/cloneDeep"); - -/** - * 深拷贝 - * @param {*} value 要深拷贝的值 - * @return {*} 返回拷贝后的值 - */ -export function cloneDeep(value) { - return _cloneDeep(value); -} - -/** - * 判断两个对象是否相等 - * @param {*} object 对象1 - * @param {*} other 对象2 - * @return {boolean} - */ -export function isEqual(object, other) { - return _isEqual(object, other); -} -/** - * 插槽 - * @member slots - * @property {string} before 输入组件前面的内容,仅当父组件是MyForm有效 - * @property {string} after 输入组件后面的内容,仅当父组件是MyForm有效 - * @property {string} label 定义字段的label内容,仅当父组件是MyForm有效 - * @property {string} error 作用域插槽,定义验证错误提示内容,仅当父组件是MyForm有效 - */ - -export default { - inject: { - myForm: { - default: null - } - }, - components: { - FormItem - }, - /** - * 属性参数 - * @member props - * @property {string} [name] 表单域 model 字段名称, 等价于 el-form-item 的 prop 参数 - * @property {string} [width] 宽度,css属性,支持像素,百分比和表达式,也可以在MyForm中统一设置itemWidth - * @property {object} [props] 输入组件参数对象,即 element 组件的参数 - * @property {Array} [options] 选项数据,数据优先顺序,options > loader > form.dictMap > form.loader - * @property {Object} [keyMap] 选项数据对象属性名称映射, 默认:{id, parentId, label, value} - * @property {boolean} [collapsible] 可收起 - * @property {boolean} [stopEnterEvent] 阻止回车事件冒泡 - * @property {string} [depend] 依赖字段名称 - * @property {*} [dependValue] 依赖字段的值,即依赖字段的值等于该值才会显示 - * @property {string} [cascade] 级联的上级字段名称,需要与loader配合加载数据 - * @property {Function} [loader] 加载数据函数,必须返回Promise - * @property {string} [dict] 字典名称,只是标识,需要与loader配合 或 表单的dictMap加载数据 - * @property {boolean} [disabled] 禁用 - * @property {boolean} [readonly] 只读 - * @property {string} [placeholder] 占位文本 - * - */ - props: { - // 表单域 model 字段名称 - name: String, - // 宽度,支持像素,百分比和表达式 - width: String, - // 输入组件参数对象 - props: Object, - // 选项数据,数据优先顺序,options > loader > form.dictMap > form.loader - options: Array, - // 选项数据对象属性名称映射 - keyMap: { - type: Object, - default() { - return { - id: "id", - label: "label", - value: "value", - disabled: "disabled", - parentId: "parentId" - }; - } - }, - // 可折叠 - collapsible: Boolean, - - // 阻止回车事件冒泡 - stopEnterEvent: Boolean, - - // 依赖字段名称 - depend: String, - - // 依赖字段的值,即依赖字段的值等于该值才会显示 - dependValue: [String, Number, Boolean, Object, Array, Function], - - // 级联的上级字段名称,需要与loader配合加载数据 - cascade: String, - - // 加载数据函数,必须返回Promise - loader: Function, - - // 字典名称,只是标识,需要与loader配合 或 表单的dictMap加载数据 - dict: String, - - // 禁用 - disabled: Boolean, - // 只读 - readonly: Boolean, - - // 占位文本 - placeholder: String, - - // 尺寸 - size: String - }, - data() { - return { - // 级联的值缓存 - cascadeValue: null, - // 当前选项数据 - currentOptions: [], - - // 正在调用loader - loading: false - }; - }, - computed: { - // 如果有name参数,并且是MyForm的子组件,即与MyForm的currentModel作双向绑定 - // 否则与组件自身的value作双向绑定 - fieldValue: { - get() { - if (this.name && this.myForm) { - const { currentModel } = this.myForm; - return _get(currentModel, this.name, this.getDefaultValue()); - } else { - return this.value || this.getDefaultValue(); - } - }, - set(val) { - if (this.name && this.myForm) { - const { currentModel } = this.myForm; - const model = cloneDeep(currentModel); - _set(model, this.name, val); - if (!isEqual(currentModel, model)) { - this.myForm.currentModel[this.name] = model[this.name]; - this.myForm.currentModel = model; - } - } else { - this.$emit("input", val); - } - } - }, - // 字段域的宽度 - itemWidth() { - // 优先取自身设置的宽度,没有就取父组件设置的公共设置宽度 - return ( - this.width || (this.myForm && this.myForm.itemWidth ? this.myForm.itemWidth : null) - ); - }, - // 字段域样式 - itemStyle() { - return { - width: this.itemWidth - }; - }, - // 输入框组件参数 - innerProps() { - return { - disabled: this.disabled, - readonly: this.readonly, - placeholder: this.placeholder, - size: this.size, - ...this.props - }; - } - }, - watch: { - itemWidth: { - immediate: true, - handler() { - this.$nextTick(() => { - this.setContentWidth(); - }); - } - }, - "myForm.currentCollapsed"(val) { - const { resetCollapsed, model } = this.myForm; - // 收起时重置表单项值 - if (val && resetCollapsed && model && this.collapsible) { - this.$nextTick(() => { - // this.fieldValue = this.myForm.model[this.name] - this.fieldValue = _get(this.myForm.model, this.name, this.getDefaultValue()); - }); - } - // 开启了折叠功能 - if (this.collapsible) { - // 折叠时先要清除事件句柄,因为原先的dom即将发生改变 - if (val) { - removeResizeListener(this.$el, this.setContentWidth); - } else { - // 如果没有加载过选项数据,触发加载函数 - if (!this.currentOptions || this.currentOptions.length === 0) { - this.loadOptions(this.myForm.currentModel, this); - } - // 展开时,待DOM生成后,重新注册事件句柄 - this.$nextTick(() => { - addResizeListener(this.$el, this.setContentWidth); - this.setContentWidth(); - }); - } - } - }, - // options 为了提高性能,不设置deep - options: { - immediate: true, - handler(val) { - this.currentOptions = cloneDeep(val) || []; - // options改变后,会触发表单验证,这里需要清楚验证错误信息 - this.$nextTick(() => { - this.clearValidate(); - }); - } - } - }, - methods: { - // 获取表单项的默认值,不同组件有不同的默认值,可在具体的组件重写这个函数 - getDefaultValue() { - return ""; - }, - // 重置字段 - resetField() { - this.$refs.elItem && this.$refs.elItem.resetField(); - }, - // 清除验证错误信息 - clearValidate() { - this.$refs.elItem && this.$refs.elItem.clearValidate(); - }, - isCollapsed() { - if (!this.myForm) return false; - - const { collapsible, currentCollapsed } = this.myForm; - // 是否已收起 - return collapsible && currentCollapsed && this.collapsible; - }, - isMatchDepend() { - // 没有设置依赖,即忽略,当已匹配处理 - if (!this.depend || !this.myForm) return true; - const model = this.myForm.currentModel; - // 依赖不支持 按路径查找 - const value = model[this.depend]; - let isMatch = true; - // 如果 dependValue 是函数,执行回调函数返回布尔值 - if (typeof this.dependValue === "function") { - isMatch = this.dependValue(value, model, this); - } else { - // 以上都不符合,即检验 dependValue 与 currentModel中的依赖属性是否一致 - isMatch = isEqual(this.dependValue, value); - } - - // 清除依赖不符合字段的值 - if (!isMatch && this.name && model[this.name]) { - this.fieldValue = this.getDefaultValue(); - delete model[this.name]; - } - return isMatch; - }, - // 传递给输入组件的插槽 - createSlots(slots = []) { - return slots.map(name => { - return ; - }); - }, - // 渲染输入组件 - renderComponent(vnode) { - // 如果组件不是MyForm的子组件,不需要包裹Item组件 - if (!this.myForm) { - return vnode; - } - // el-form-item 作用域插槽 - const scopedSlots = this.$scopedSlots.error - ? { - error: props => ( -
- {this.$scopedSlots.error(props)} -
- ) - } - : null; - - // 是否已收起 - const collapsed = this.isCollapsed(); - // 是否符合依赖项 - const isMatched = this.isMatchDepend(); - - return ( - - {!collapsed && isMatched ? ( - - {// label 插槽 - this.$slots.label ? ( - - ) : null} - {this.$slots.before} - {vnode} - {this.$slots.after} - - ) : ( - // Vue组件必须要有一个根DOM,创建一个隐藏占位元素 -
{this.name}
- )} -
- ); - }, - // 继承输入组件暴露的方法 - extendMethods(ref, names = []) { - if (!ref) return; - - names.forEach(name => { - // 子组件的方法加到实例 - this[name] = (...args) => { - ref[name].apply(ref, args); - }; - }); - }, - // 设置el-form-item内部的内容区宽度 - setContentWidth() { - // 字段域没有设置宽度,默认自适应,不需要处理 - if (!this.itemWidth || !this.$el) return; - const content = this.$el.querySelector(".el-form-item__content"); - const label = this.$el.querySelector(".el-form-item__label"); - if (content) { - const rect = label ? label.getBoundingClientRect() : { width: 0 }; - const itemWidth = this.$el.getBoundingClientRect().width; - const contentWidth = itemWidth - rect.width; - setStyle(content, { width: `${contentWidth}px` }); - } - }, - // 阻止回车事件冒泡 - stopEvent(e) { - if (this.stopEnterEvent) { - e.stopPropagation(); - } - }, - // 加载选项数据 - loadOptions(model) { - // 已收起的,不需要处理 - if (this.isCollapsed()) return; - - // 如果不符合依赖,不处理 - if (!this.isMatchDepend()) return; - - // 数据优先顺序,options > loader > form.dictMap > form.loader - if (this.options) { - this.currentOptions = cloneDeep(this.options); - return; - } - - if (this.loader) { - this.loading = true; - this.loader(model, this) - .then(res => { - this.currentOptions = cloneDeep(res); - }) - .finally(() => { - this.loading = false; - }); - return; - } - - // 无form容器,终止 - if (!this.myForm) return; - - if (this.dict) { - const { dictMap } = this.myForm; - const options = (dictMap || {})[this.dict]; - // 建立与表单的字典数据引用 - if (options) { - this.currentOptions = options; - return; - } - } - - if (this.myForm.loader) { - this.loading = true; - this.myForm - .loader(model, this) - .then(res => { - this.currentOptions = cloneDeep(res); - }) - .finally(() => { - this.loading = false; - }); - } - }, - // 响应currentModel改变处理级联加载数据 - handleWatch(model) { - // 级联上级的值 - const val = model[this.cascade]; - // 与上次的值不一致即重新获取数据 - if (!isEqual(this.cascadeValue, val)) { - this.fieldValue = this.getDefaultValue(); - this.cascadeValue = val; - this.loadOptions(model); - } - }, - // 绑定级联 - bindCascade() { - if (this.cascade && this.myForm) { - const model = this.myForm.currentModel; - this.cascadeValue = model[this.cascade]; - this.unwatch = this.$watch("myForm.currentModel", this.handleWatch, { deep: true }); - } - }, - // 销毁级联事件句柄 - unbindCascade() { - this.unwatch && this.unwatch(); - } - }, - mounted() { - addResizeListener(this.$el, this.setContentWidth); - }, - created() { - let model = null; - if (this.myForm) { - this.myForm.addItem(this); - model = this.myForm.currentModel; - } - - this.loadOptions(model, this); - this.bindCascade(); - }, - beforeDestroy() { - removeResizeListener(this.$el, this.setContentWidth); - this.unbindCascade(); - if (this.myForm) { - this.myForm.removeItem(this); - } - } -}; diff --git a/src/cool/modules/task/components/cron/cron.vue b/src/cool/modules/task/components/cron/cron.vue index 84d39db..dca67db 100644 --- a/src/cool/modules/task/components/cron/cron.vue +++ b/src/cool/modules/task/components/cron/cron.vue @@ -3,7 +3,7 @@ {{ text.Seconds.name }} -
+
{{ text.Seconds.every @@ -59,9 +59,10 @@
+ {{ text.Minutes.name }} -
+
{{ text.Minutes.every @@ -117,9 +118,10 @@
+ {{ text.Hours.name }} -
+
{{ text.Hours.every @@ -175,9 +177,10 @@
+ {{ text.Day.name }} -
+
{{ text.Day.every }} @@ -319,9 +322,10 @@
+ {{ text.Month.name }} -
+
{{ text.Month.every @@ -378,9 +382,10 @@
+ {{ text.Year.name }} -
+
{{ text.Year.every @@ -443,10 +448,10 @@
-
- - {{ text.Save }} - {{ text.Close }} + +
@@ -457,7 +462,7 @@ import Language from "./cn"; export default { name: "vue-cron", - props: ["data", "i18n", "showYear"], + props: ["value", "data", "i18n", "showYear"], data() { return { @@ -733,7 +738,8 @@ export default { getValue() { return this.cron; }, - change() { + save() { + this.$emit("input", this.cron); this.$emit("change", this.cron); this.close(); }, @@ -759,16 +765,24 @@ export default { } }; - diff --git a/src/cool/modules/task/components/cron/index.js b/src/cool/modules/task/components/cron/index.js index 4f085fb..df350d0 100644 --- a/src/cool/modules/task/components/cron/index.js +++ b/src/cool/modules/task/components/cron/index.js @@ -1,11 +1,8 @@ import Cron from "./cron"; -import Base from "./base"; export default { name: "cl-cron", - mixins: [Base], - components: { Cron }, @@ -15,66 +12,58 @@ export default { placeholder: { type: String, default: "请输入定时策略" - } + }, + disabled: Boolean, + readonly: Boolean }, data() { return { - cronPopover: false, + visible: false, cron: "" }; }, watch: { - cron: { - handler(val) { - this.fieldValue = val; - this.$emit("change", val); - } - }, value: { immediate: true, handler(val) { this.cron = val; } }, - fieldValue: { - immediate: true, + cron: { handler(val) { - this.cron = val; + this.$emit("input", val); + this.$emit("change", val); } } }, methods: { - changeCron(val) { - this.cron = val; - }, - hidePopover() { - this.cronPopover = false; + close() { + this.visible = false; } }, render() { - const vnode = ( - + return ( + ); - return this.renderComponent(vnode); } };