123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748 |
- import _ from 'lodash'
- import {Lib, lookupScope} from './lib'
- import {ajax} from "./config";
- import {Model} from 'src/types';
- import {msg, showErrorDialog} from "../message";
- export const SIMPLE_RE = /^(?:\{(?:(\d+)|([a-z_][\w\.]*))\})$/i
- /**
- * 对某个表达式进行求值
- * a:{query.a},b:{query.b} -> a:aValue,b:bValue
- *
- * @example
- * calcExpress(cc.viewModel.data, "WH_ID:{query.WH_ID},C:{theGrid.selection.data.WH_ID}")
- * 计算出来的值是: "WH_ID:queryWhId,C:JH000000001"
- *
- * @param data 数据环境对象
- * @param express 表达式对象
- */
- export function calcExpress(data, express) {
- let result = express
- if (SIMPLE_RE.test(express)) {
- // '{foo}' 简单表达式
- const path = express.substring(1, express.length - 1);
- return _.get(data, path)
- }
- while (true) {
- const mlist = result.match(/{(.*?)}/)
- if (!mlist) {
- break
- }
- const pathC = mlist[0] // {query.a}
- const path = mlist[1] // query.a
- let value = _.get(data, path)
- result = result.replaceAll(pathC, value || '')
- }
- return result
- }
- /**
- * 对个对象进行表达式求值,不用回调
- * @example
- * calcObjectFlat({query:{a:'aValue',b1:'b1Value',b2:'b2Value',d1:1,d2:2}}, { a:'{query.a}', b:{b1:'{query.b1}', b2:'{query.b2}'},c:'aa',d:['{query.d1}','{query.d2}'] })
- *
- * {
- * a: '{query.a}',
- * b: {
- * b1: '{query.b1}',
- * b2: '{query.b2}',
- * },
- * c: 'aa',
- * d: [
- * '{query.d1}',
- * '{query.d2}'
- * ]
- * }
- *
- * 计算结果为
- * {
- * a: 'aValue',
- * b: {
- * b1: 'b1Value',
- * b2: 'b2Value'
- * },
- * c: 'aa'
- * d: [
- * '1',
- * '2'
- * ]
- * }
- *
- * @param data
- * @param paramObject
- */
- export function calcObjectFlat(data, paramObject) {
- const result = _.cloneDeep(paramObject)
- const trav = (param) => {
- _.forOwn(param, (value, key) => {
- if (_.isPlainObject(value)) {
- // 深度递归,对子对象进行求解
- trav(value)
- } else if (_.isString(value)) {
- // 字符串直接用 calcExpress 表达式求解
- param[key] = calcExpress(data, param[key])
- } else if (_.isArray(value)) {
- // 数组求解
- _.each(value, (v, idx) => {
- value[idx] = calcExpress(data, v)
- })
- }
- })
- }
- trav(result)
- return result
- }
- /**
- * 根据表达式进入写值
- * express="{query.a}" 写值就是 viewModel.set('query.a', value)
- * express="test-{query.a}" 写值就会失败
- *
- * @example
- * tryWriteByExpress(cc.viewModel, "{query.WH_ID}", "111")
- * 写值成功
- *
- * tryWriteByExpress(cc.viewModel, "test-{query.WH_ID}", "111")
- * 写值失败
- *
- * @param viewModel VM对象
- * @param express 表达式对象
- * @param value 目标值
- */
- export function tryWriteByExpress(viewModel, express, value) {
- if (SIMPLE_RE.test(express)) {
- // '{foo}' 简单表达式
- express = express.substring(1, express.length - 1);
- viewModel.set(express, value)
- }
- }
- /**
- * 尝试根据含表达式的对象回写, calcObjectFlat 的逆向方法
- * @example
- * tryWriteObject({ a:'{query.a}', b:{b1:'{query.b1}', b2:'{query.b2}'},c:'aa',d:['{query.d1}','{query.d2}']}, {a:'aValue', b:{b1:'b1Value', b2:'b2Value'}, c:'aa', d:[1,2]})
- *
- * expressObject:
- * {
- * a: '{query.a}',
- * b: {
- * b1: '{query.b1}',
- * b2: '{query.b2}',
- * },
- * c: 'aa',
- * d: [
- * '{query.a}',
- * '{query.b2}'
- * ]
- * }
- *
- * valueObject:
- * {
- * a: 'aValue',
- * b: {
- * b1: 'b1Value',
- * b2: 'b2Value'
- * },
- * c: 'aa'
- * c: [
- * 'aValue',
- * 'b2Value'
- * ]
- * }
- *
- * 系统会尝试回写
- * viewModel.set('query.a', 'aValue')
- * viewModel.set('query.b1', 'b1Value')
- * viewModel.set('query.b2', 'b2Value')
- *
- * @param expressObject 含表达式的对象
- * @param valueObject 表达式计算完成之后的结果对象
- * @param writeFn 写入的方法 (path, value)=>void
- */
- export function tryWriteObject(expressObject, valueObject, writeFn) {
- const trav = (pathPrefix) => {
- let parent = expressObject
- if (_.size(pathPrefix) > 1) {
- parent = _.get(parent, pathPrefix.substring(1))
- }
- _.forOwn(parent, (value, key) => {
- if (_.isPlainObject(value)) {
- // 深度递归,对子对象进行求解
- trav(pathPrefix + "." + key)
- } else if (_.isString(value)) {
- // 字符串直接用 calcExpress 表达式求解
- if (SIMPLE_RE.test(value)) {
- // If we have '{foo}' alone it is a literal 简单表达式
- const targetPath = value.substring(1, value.length - 1);
- const targetValue = _.get(valueObject, (pathPrefix + "." + key).substr(1))
- if (!writeFn) {
- console.log(`viewModel.set('${targetPath}', '${targetValue}')`)
- } else {
- writeFn(targetPath, targetValue)
- }
- }
- } else if (_.isArray(value)) {
- _.each(value, (v, idx) => {
- if (SIMPLE_RE.test(v)) {
- const targetPath = (pathPrefix + "." + key).substr(1) + "[" + idx + "]";
- const targetValue = _.get(valueObject, (pathPrefix + "." + key).substr(1) + "[" + idx + "]")
- if (!writeFn) {
- console.log(`viewModel.set('${targetPath}', '${targetValue}')`)
- } else {
- writeFn(targetPath, targetValue)
- }
- }
- })
- }
- })
- }
- trav("")
- }
- /**
- * 对多个表达式进行求值. 异步回调的方式返回
- * {
- * a: 1,
- * b: '{someBind}',
- * c: ['a', 'b', 'c'],
- * d: ['a', 'b', '{someBind}'],
- * e: {
- * y: 1,
- * z: 2
- * },
- * f: {
- * y: 1,
- * z: '{someBind}'
- * }
- * }
- *
- * // Will produce
- * {
- * b: value,
- * d: ['a', 'b', value],
- * f: {
- * y: 1,
- * z: value
- * }
- * }
- * @param viewModel scope.viewModel对象
- * @param paramObject 求值对象
- */
- export function calcObject(viewModel, paramObject) {
- // new Ext.app.bind.Multi({a:'1',b:'ddd{query.WH_ID}'},currentScope.viewModel,function(v){console.log(v)},currentScope, {single: true})
- return new Promise(resolve => {
- const schedule = new Ext.app.bind.Multi(
- paramObject,
- viewModel,
- (ret) => {
- schedule.destroy()
- // 从 Ext.data.Model 对象转换为 js-object 对象
- ret = toPlainObject(ret)
- resolve(ret)
- },
- viewModel,
- {single: true})
- })
- }
- /**
- * 用于任意组件 Ext.Component 构造时,获取当前组件对应的表格(如果不是 grid.columns 对象就会返回 undefined)
- * @param config 组件构造函数传入的 config 配置文件
- */
- export function getParentGrid(config) {
- return config.$initParent?.grid
- }
- /**
- * 动态的为 combo 或 columns.combo 设置下拉框的值
- * @param sender 目标对象
- * @param config 目标对象的配置(在构造函数之前也可以)
- * @param getDictFn 获取字典的方法
- * @param bizKey 传入字典的参数
- */
- export function setComboStore(sender, config, getDictFn, bizKey) {
- if (sender.$className === 'Ext.form.field.ComboBox') {
- getDictFn(bizKey, (r) => {
- if (sender.el?.dom) {
- // 异步回传
- sender.setStore(new Ext.data.Store(r))
- } else {
- // 同步回传
- config.store = new Ext.data.Store(r)
- }
- })
- return
- } else if (sender.xtype === 'gridcolumn') {
- const grid = getParentGrid(config)
- const {editor, renderer} = config
- getDictFn(bizKey, (r) => {
- if (sender.rendered) {
- // 已经渲染出来了, 用方法进行修改
- const editor = sender.getEditor()
- if (editor && editor.xtype === 'combo') {
- const valueField = r.field[0]
- const displayField = r.field[1]
- editor.valueField = valueField
- editor.setDisplayField(displayField)
- editor.setStore(new Ext.data.Store({
- field: ['id', 'text'],
- data: [
- {id: "Y", text: "启用"},
- {id: "N", text: "禁用"},
- {id: "D", text: "删除"},
- ]
- }))
- }
- } else {
- // 没有渲染之前,修改 config 即可
- if (editor && editor.xtype === 'combo') {
- // 带编辑模式
- editor.store = new Ext.data.Store(r)
- }
- }
- const renderer = (value, metaData) => {
- const valueField = r.field[0]
- const displayField = r.field[1]
- _.each(r.data, row => {
- // 从 valueField 找到要显示的 displayField
- if (row[valueField] == value) {
- value = row[displayField]
- return false
- }
- })
- return value
- }
- if (sender.rendered) {
- // 已经渲染出来了, 对列进行渲染
- sender.renderer = renderer
- sender.getView().refresh()
- } else {
- config.renderer = renderer
- }
- })
- return
- }
- throw new TypeError("无法识别的组件类型")
- }
- /**
- * 调用服务器 Ajax
- */
- export function invokeServer(url: string, ...args: any[]) {
- // @ts-ignore
- return ajax.func({
- url: url,
- method: 'invoke',
- args: args
- })
- }
- export function clearViewModelValues(viewModel, propertyName) {
- const dd = _.get(viewModel.getData(), propertyName)
- _.forOwn(dd, (value, key) => {
- viewModel.set(propertyName + '.' + key, '')
- })
- }
- export function reloadGrid(scope, gridRefName) {
- scope.refs[gridRefName]?.reload()
- }
- /**
- * 将 Ext.data.Model 对象 (及子属性) 转换为 js.object 对象
- */
- export function toPlainObject(obj) {
- if (obj.isModel) {
- obj = obj.data
- }
- _.forOwn(obj, (v, k) => {
- // Ext.data.Model.constructor
- if (!v) {
- return
- }
- if (v.isModel) {
- v = v.data
- }
- if (typeof v === 'object') {
- obj[k] = toPlainObject(v)
- } else {
- obj[k] = v
- }
- })
- return obj
- }
- class SystemEventFu {
- @Lib({
- title: '提交表单',
- author: '罗一帆',
- createAt: '2021-07-02',
- updateAt: '2021-07-02',
- type: 'system',
- category: '表单',
- args: [
- {
- type: 'string',
- title: 'groovy 服务路径',
- name: 'groovyUrl',
- },
- {
- type: 'object',
- title: '参数的 lookup 表达式, 如果不填 默认提交所有的 viewModel.data',
- name: 'arg0',
- allowEmpty: true,
- }
- ]
- })
- formCommit(groovyUrl: string, arg0: any) {
- return function (sender) {
- const scope = lookupScope(sender)
- const valid = scope.down('form').isValid()
- if (!valid) {
- return
- }
- scope.setLoading(true)
- let data = scope.viewModel.data
- if (arg0) {
- data = calcObjectFlat(data, arg0)
- }
- invokeServer(groovyUrl, data).then(res => {
- if (res.success) {
- scope.dialogSuccess(res)
- } else {
- showErrorDialog(res.msg || '未知错误', sender)
- }
- }).catch((e) => {
- const msg = e.response?.data?.msg
- showErrorDialog(msg || e.toString(), sender)
- }).finally(() => {
- scope.setLoading(false)
- })
- }
- }
- @Lib({
- title: '对话框成功回调',
- author: '罗一帆',
- createAt: '2021-07-02',
- updateAt: '2021-07-02',
- type: 'system',
- category: '对话框',
- args: []
- })
- dialogSuccess() {
- debugger
- }
- @Lib({
- title: '清空 viewModel 某个属性',
- author: '罗一帆',
- createAt: '2021-07-02',
- updateAt: '2021-07-02',
- type: 'system',
- category: '表单',
- args: [
- {
- type: 'viewModel',
- title: 'propertyName 属性路径',
- name: 'propertyName',
- }
- ]
- })
- clearViewModelValues(propertyName: string) {
- return function (sender) {
- const scope = lookupScope(sender)
- clearViewModelValues(scope.viewModel, propertyName)
- }
- }
- @Lib({
- title: '清空 viewModel 某个属性,并刷新表格',
- author: '罗一帆',
- createAt: '2021-07-02',
- updateAt: '2021-07-02',
- type: 'system',
- category: '表单',
- args: [
- {
- type: 'viewModel',
- title: 'propertyName 属性路径',
- name: 'propertyName',
- },
- {
- type: 'refs',
- title: 'gridRef 表格引用名',
- allowEmpty: true,
- name: 'gridRefName',
- }
- ]
- })
- clearViewModelReloadGrid(propertyName: string, gridRefName?: string) {
- return function (sender) {
- const scope = lookupScope(sender)
- clearViewModelValues(scope.viewModel, propertyName)
- if (!gridRefName) {
- scope.down('grid')?.reload()
- } else {
- scope.refs[gridRefName]?.reload()
- }
- }
- }
- @Lib({
- title: '刷新表格',
- author: '罗一帆',
- createAt: '2021-07-02',
- updateAt: '2021-07-02',
- type: 'system',
- category: '表单',
- args: [
- {
- type: 'refs',
- title: 'gridRef 表格引用名, 不填写的情况下刷新所有',
- allowEmpty: true,
- name: 'gridRefName',
- }
- ]
- })
- reloadGrid(gridRefName: string) {
- return function (sender) {
- const scope = lookupScope(sender)
- if (!gridRefName) {
- scope.down('grid')?.reload()
- } else {
- scope.refs[gridRefName]?.reload()
- }
- }
- }
- @Lib({
- title: '显示对话框',
- author: '罗一帆',
- createAt: '2021-07-02',
- updateAt: '2021-07-02',
- type: 'system',
- category: '对话框',
- args: [
- {
- type: 'module',
- title: '业务模块名',
- name: 'url',
- },
- {
- type: 'object',
- title: '参数数据 lookup 表达式',
- name: 'lookupForData',
- allowEmpty: true,
- },
- {
- type: 'event',
- title: '成功回调',
- name: 'successCallback',
- allowEmpty: true,
- }
- ]
- })
- showDialog(url: string, lookupForData: any, successCallback) {
- return function (sender) {
- const scope = lookupScope(sender)
- const data = scope.viewModel.data
- const param = calcObjectFlat(data, lookupForData)
- // @ts-ignore
- require([url], (module) => {
- const ScopeClass = module.default
- const scope = new ScopeClass()
- scope.success = successCallback
- scope.showDialog(sender, {}, {data: param})
- })
- }
- }
- @Lib({
- title: '弹出查找框(不借助 search)',
- author: '罗一帆',
- createAt: '2021-07-02',
- updateAt: '2021-07-02',
- type: 'system',
- category: '对话框',
- args: [
- {
- type: 'module',
- title: '模块名 (WidgetDialog)',
- name: 'widgetUrl',
- },
- {
- type: 'object',
- title: 'lookup 映射关系',
- name: 'lookupSetting',
- allowEmpty: true,
- }
- ]
- })
- showWidget(widgetUrl, lookup, params) {
- return function (sender, queryValue) {
- showWidget(widgetUrl, lookup, params, sender, queryValue)
- }
- }
- @Lib({
- title: '根据 lookup 清空 viewModel',
- author: '罗一帆',
- createAt: '2021-07-05',
- updateAt: '2021-07-05',
- type: 'system',
- category: '表单',
- args: [
- {
- type: 'viewModel',
- title: 'lookup 设值',
- name: 'lookup',
- },
- ]
- })
- clearViewModelByLookup(lookup) {
- return function (sender) {
- clearViewModelByLookup(sender, lookup)
- }
- }
- @Lib({
- title: '关闭对话框',
- author: '罗一帆',
- createAt: '2021-07-05',
- updateAt: '2021-07-05',
- type: 'system',
- category: '对话框',
- args: [
- {
- type: 'event',
- title: '对话框的返回值回调',
- name: 'callBack',
- },
- ]
- })
- closeMe(callBack) {
- return function (sender) {
- const scope = lookupScope(sender)
- scope.close()
- if (callBack) {
- callBack.call(sender)
- }
- }
- }
- }
- export function clearViewModelByLookup(sender, lookup) {
- if (_.isPlainObject(lookup)) {
- const parentScope = lookupScope(sender)
- _.forOwn(lookup, (value, key) => {
- if (SIMPLE_RE.test(value)) {
- // '{foo}' 简单表达式
- const path = value.substring(1, value.length - 1);
- if (path !== 'queryValue') {
- parentScope.viewModel.set(path, '')
- }
- }
- })
- }
- }
- export function showWidget(widgetUrl, lookup, params, sender, queryValue, vjson = {}) {
- const parentScope = lookupScope(sender)
- const me = sender
- // @ts-ignore
- require([widgetUrl], (widgetScope) => {
- const WidgetScopeClass = widgetScope.default
- widgetScope = new WidgetScopeClass()
- // 传递进 widget.model 的数据
- const widgetDialogData = calcObjectFlat({
- queryValue: queryValue,
- ...parentScope.viewModel.data
- }, lookup)
- _.map(params, (value, key) => {
- widgetDialogData[key] = value
- })
- widgetScope.parentScope = parentScope
- widgetScope.searchWidgetSuccess = (data) => {
- if (typeof lookup === 'string') {
- // lookup 是字符串的情况下,就是取某个列作为 value 值
- me.setValue(data[lookup])
- return
- }
- /**
- * lookup: {
- * // 扩展到 viewModel 的值做更改
- * WH_CODE: "{queryValue}",
- * WH_NAME: "{query.WH_NAME}",
- * }
- */
- if (_.isPlainObject(lookup)) {
- const parentScope = lookupScope(sender)
- tryWriteObject(lookup, data, (path, value) => {
- if (path === 'queryValue') {
- me.setValue(value)
- } else {
- parentScope.viewModel.set(path, value)
- }
- }
- )
- }
- return true
- }
- widgetScope.showDialog(sender, vjson, {data: widgetDialogData})
- })
- }
- /**
- * 停止事件的默认行为
- * @param e
- */
- export function stopEvent(e) {
- e.preventDefault()
- e.stopPropagation()
- // @ts-ignore
- window.event.cancelBubble = true
- e.returnValue = false;
- e.cancelBubble = true;
- }
|