23 changed files with 1952 additions and 309 deletions
@ -0,0 +1,174 @@ |
|||
<template> |
|||
<div class="yv-json-editor"> |
|||
<textarea ref="_textarea"></textarea> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import _ from 'lodash' |
|||
// codemirror基础资源引入 |
|||
import CodeMirror from "codemirror"; |
|||
import "codemirror/lib/codemirror.css"; |
|||
import "codemirror/mode/javascript/javascript.js"; |
|||
|
|||
// 折叠资源引入:开始 |
|||
import "codemirror/addon/fold/foldgutter.css"; |
|||
import "codemirror/addon/fold/foldcode.js"; |
|||
import "codemirror/addon/fold/brace-fold.js"; |
|||
import "codemirror/addon/fold/comment-fold.js"; |
|||
import "codemirror/addon/fold/indent-fold.js"; |
|||
import "codemirror/addon/fold/foldgutter.js"; |
|||
import "codemirror/addon/hint/show-hint.css"; |
|||
// 折叠资源引入:结束 |
|||
|
|||
// 括号匹配 |
|||
import "codemirror/addon/edit/matchbrackets.js"; |
|||
|
|||
// 搜索资源引入:开始 |
|||
import "codemirror/addon/scroll/annotatescrollbar.js"; |
|||
import "codemirror/addon/search/matchesonscrollbar.js"; |
|||
import "codemirror/addon/search/match-highlighter.js"; |
|||
import "codemirror/addon/search/jump-to-line.js"; |
|||
|
|||
import "codemirror/addon/dialog/dialog.js"; |
|||
import "codemirror/addon/dialog/dialog.css"; |
|||
import "codemirror/addon/search/searchcursor.js"; |
|||
import "codemirror/addon/search/search.js"; |
|||
// 搜索资源引入:结束 |
|||
|
|||
//光标行背景高亮,配置里面也需要styleActiveLine设置为true |
|||
import "codemirror/addon/selection/active-line.js"; |
|||
|
|||
// 代码检查错误 |
|||
import "codemirror/addon/lint/lint.css"; |
|||
import "codemirror/addon/lint/lint.js"; |
|||
import "codemirror/addon/lint/json-lint.js"; |
|||
|
|||
export default { |
|||
props: { |
|||
modelValue: String, |
|||
defaultValue: {type: String, default: ''}, |
|||
readonly: {type: Boolean, default: false}, |
|||
}, |
|||
emits: [ |
|||
'update:modelValue', |
|||
], |
|||
data() { |
|||
return { |
|||
// editor: undefined, |
|||
// meHeight: 'auto', |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
this.init() |
|||
}) |
|||
}, |
|||
beforeUnmount() { |
|||
// debugger |
|||
if (this.editor != null) { |
|||
this.editor.toTextArea(); |
|||
this.editor = null; |
|||
} |
|||
}, |
|||
methods: { |
|||
appendText(text) { |
|||
this.editor.setValue(this.editor.getValue() + text) |
|||
}, |
|||
scrollToButtom() { |
|||
const editor = this.editor |
|||
const info = editor.getScrollInfo() |
|||
const height = info.height |
|||
editor.scrollTo(0, height) |
|||
}, |
|||
init() { |
|||
this.editor = CodeMirror.fromTextArea(this.$refs._textarea, { |
|||
value: this.modelValue, |
|||
viewportMargin: Infinity, |
|||
// JS高亮显示 |
|||
mode: "application/json", |
|||
indentUnit: 2, // 缩进单位,默认2 |
|||
// 在缩进时,是否需要把 n*tab宽度个空格替换成n个tab字符,默认为false |
|||
indentWithTabs: false, |
|||
// 自动缩进,设置是否根据上下文自动缩进(和上一行相同的缩进量)。默认为true |
|||
smartIndent: true, // 是否智能缩进 |
|||
// 是否在编辑器左侧显示行号 |
|||
lineNumbers: false, |
|||
// 括号匹配 |
|||
matchBrackets: true, |
|||
// 开启代码折叠 |
|||
lineWrapping: false, |
|||
foldGutter: true, |
|||
gutters: [ |
|||
"CodeMirror-linenumbers", |
|||
"CodeMirror-foldgutter", |
|||
"CodeMirror-lint-markers", |
|||
], |
|||
readOnly: this.readonly, |
|||
// gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"], |
|||
// 光标行高亮 |
|||
styleActiveLine: true, |
|||
theme: 'default innerMirror', |
|||
}); |
|||
window['$editor'] = this.editor |
|||
|
|||
// 监听编辑器的change事件 |
|||
this.editor.on("change", () => { |
|||
// 触发v-model的双向绑定 |
|||
this.$emit("update:modelValue", this.editor.getValue()); |
|||
}); |
|||
this.editor.on("cursorActivity", (cm) => { |
|||
// console.log(cm) |
|||
// this.editor.showHint(); |
|||
}); |
|||
// this.editor.on("inputRead", () => { |
|||
// this.editor.showHint(); |
|||
// }); |
|||
|
|||
if (this.modelValue) { |
|||
this.editor.setValue(this.modelValue); |
|||
} else { |
|||
if (this.defaultValue) { |
|||
this.editor.setValue(this.defaultValue); |
|||
} |
|||
} |
|||
}, |
|||
}, |
|||
computed: {}, |
|||
watch: { |
|||
modelValue: { |
|||
handler(newValue) { |
|||
if (this.editor && typeof newValue === 'string' && newValue !== this.editor.getValue()) { |
|||
// 触发v-model的双向绑定 |
|||
this.editor.setValue(newValue); |
|||
} |
|||
}, |
|||
}, |
|||
readonly: { |
|||
handler(val) { |
|||
if (this.editor) { |
|||
this.editor.setOption("readOnly", val); |
|||
} |
|||
}, |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
<style lang="less"> |
|||
.yv-json-editor { |
|||
height: 100%; |
|||
|
|||
.CodeMirror { |
|||
width: 100%; |
|||
height: auto !important; |
|||
min-height: 100px; |
|||
overflow-y: auto; |
|||
overflow-x: auto; |
|||
|
|||
font-size: 16px; |
|||
color: #333; |
|||
font-family: Helvetica, -apple-system, system-ui, Ubuntu, Microsoft YaHei, sans-serif; |
|||
background-color: #FFF; |
|||
border: 1px solid #ece2e2; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,51 @@ |
|||
<template> |
|||
<div> |
|||
<el-button size="small" link type="danger" @click="onClick">{{ params.action ?? '删除' }}</el-button> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import _ from 'lodash' |
|||
import {defineComponent, toRaw, reactive} from "vue" |
|||
import {ElButton} from 'element-plus' |
|||
|
|||
// const props = defineProps({ |
|||
// params: Object, |
|||
// value: null, |
|||
// }) |
|||
|
|||
export default defineComponent({ |
|||
components: {ElButton}, |
|||
name: "DeleteCellRenderer", |
|||
props: ['value', 'params'], |
|||
setup(props) { |
|||
const data = reactive({}) |
|||
|
|||
function onClick() { |
|||
const yvAggrid = props.params.context.componentParent |
|||
if (yvAggrid.$props.data) { |
|||
props.params.api.applyTransaction({ |
|||
remove: [props.params.data], |
|||
}) |
|||
|
|||
// 删除 this.params.rowIndex |
|||
yvAggrid.$props.data.splice(props.params.rowIndex, 1) |
|||
} |
|||
if (_.isArray(yvAggrid.$props.modelValue)) { |
|||
if (props.params.action) { |
|||
// 其他按钮 |
|||
yvAggrid.onActionClick(props.params.action, props.params) |
|||
|
|||
} else { |
|||
// 删除 this.params.rowIndex |
|||
_.remove(yvAggrid.$props.modelValue, (r) => r._rid === props.params.data._rid) |
|||
// yvAggrid.$props.modelValue.splice(props.params.rowIndex, 1) |
|||
} |
|||
} |
|||
} |
|||
|
|||
return { |
|||
data, onClick, |
|||
} |
|||
} |
|||
}) |
|||
</script> |
|||
@ -0,0 +1,259 @@ |
|||
<template> |
|||
<el-switch v-if="containsData" v-model="boolValue" label="" |
|||
ref="_inner" |
|||
:before-change="onBeforeChange" |
|||
@change="onChange" |
|||
size="small" /> |
|||
</template> |
|||
<script> |
|||
import _ from 'lodash' |
|||
import { defineComponent, reactive, onMounted, nextTick, defineProps, getCurrentInstance } from 'vue' |
|||
import { ElSwitch } from 'element-plus' |
|||
import { runEvent } from '@/utils/webutils.js' |
|||
|
|||
export default { |
|||
props: ['params'], |
|||
components: { ElSwitch }, |
|||
data(props) { |
|||
return { |
|||
value: null, |
|||
containsData: typeof props.params.data === 'object', |
|||
isTreeNode: typeof props.params.eParentOfValue === 'object', |
|||
boolValue: null, |
|||
isActive: false, |
|||
allowEdit: props.params.allowEdit |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.value = this.params.value |
|||
this.$nextTick(() => { |
|||
this.isActive = true |
|||
}) |
|||
let value = this.params.value |
|||
this.boolValue = false |
|||
if (this.params.editor.convType === 'bool') { |
|||
if (`${value}` === 'true') { |
|||
this.boolValue = true |
|||
} |
|||
|
|||
} else { |
|||
if (this.params.editor.activeValue) { |
|||
if (`${value}` === this.params.editor.activeValue) { |
|||
this.boolValue = true |
|||
} |
|||
} else { |
|||
// 没有激活值 |
|||
if (`${value}` === '1' || `${value}` === 'true' || `${value}` === 'Y') { |
|||
this.boolValue = true |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
getValue() { |
|||
return this.value |
|||
}, |
|||
onBeforeChange() { |
|||
if (this.isActive === false) { |
|||
return true |
|||
} |
|||
|
|||
const allowEdit = this.allowEdit |
|||
if (allowEdit) { |
|||
const f = new Function('param', 'scope', allowEdit) |
|||
const r = f.call(this.params.scope, this.params, this.params.scope) |
|||
if (r === false) { |
|||
// 不允许修改 |
|||
return false |
|||
} |
|||
} |
|||
|
|||
// 其他情况都允许修改 |
|||
return true |
|||
}, |
|||
onChange(boolValue) { |
|||
const params = this.params |
|||
if (!this.isActive) { |
|||
return |
|||
} |
|||
|
|||
let newValue = boolValue |
|||
this.boolValue = boolValue |
|||
|
|||
const convType = this.params.editor?.convType ?? 'bool' |
|||
|
|||
if (convType === 'bool') { |
|||
if (`${boolValue}` === 'true') { |
|||
newValue = true |
|||
} else { |
|||
newValue = false |
|||
} |
|||
|
|||
} else if (convType === 'num') { |
|||
if (boolValue) { |
|||
newValue = parseInt(params.editor.activeValue ?? '1') |
|||
} else { |
|||
newValue = parseInt(params.editor.inactiveValue ?? '0') |
|||
} |
|||
|
|||
} else if (convType === 'str') { |
|||
if (boolValue) { |
|||
newValue = params.editor.activeValue |
|||
} else { |
|||
newValue = params.editor.inactiveValue |
|||
} |
|||
} |
|||
|
|||
const dataIndex = this.params.colDef?.field || '' |
|||
|
|||
if (dataIndex.includes('.')) { |
|||
_.set(this.params.data, dataIndex, newValue) |
|||
} else { |
|||
params.node.data[params.colDef.field] = newValue |
|||
} |
|||
|
|||
const yvAggrid = this.params.context.componentParent |
|||
yvAggrid.onCellValueChanged({ |
|||
...params, |
|||
newValue, |
|||
value: newValue, |
|||
valueFormatted: `${newValue}` |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
|
|||
// export default defineComponent({ |
|||
// name: "YvAggridCheckbox", |
|||
// props: ['value', 'params'], |
|||
// components: {ElSwitch}, |
|||
// setup(props) { |
|||
// const data = reactive({ |
|||
// containsData: typeof props.params.data === 'object', |
|||
// isTreeNode: typeof props.params.eParentOfValue === 'object', |
|||
// boolValue: null, |
|||
// isActive: false, |
|||
// allowEdit: props.params.allowEdit |
|||
// }) |
|||
// |
|||
// function getValue() { |
|||
// return props.value; |
|||
// } |
|||
// |
|||
// function onBeforeChange() { |
|||
// if (data.isActive === false) { |
|||
// return true |
|||
// } |
|||
// |
|||
// const allowEdit = data.allowEdit |
|||
// if (allowEdit) { |
|||
// const f = new Function('param', 'scope', allowEdit) |
|||
// const r = f.call(props.params.scope, props.params, props.params.scope) |
|||
// if (r === false) { |
|||
// // 不允许修改 |
|||
// return false |
|||
// } |
|||
// } |
|||
// |
|||
// // 其他情况都允许修改 |
|||
// return true |
|||
// } |
|||
// |
|||
// function onChange(boolValue) { |
|||
// const params = props.params |
|||
// if (!data.isActive) { |
|||
// return |
|||
// } |
|||
// |
|||
// let newValue = boolValue |
|||
// data.boolValue = boolValue |
|||
// |
|||
// const convType = props.params.editor?.convType ?? 'bool' |
|||
// |
|||
// if (convType === 'bool') { |
|||
// if (`${boolValue}` === 'true') { |
|||
// newValue = true |
|||
// } else { |
|||
// newValue = false |
|||
// } |
|||
// |
|||
// } else if (convType === 'num') { |
|||
// if (boolValue) { |
|||
// newValue = parseInt(params.editor.activeValue ?? '1') |
|||
// } else { |
|||
// newValue = parseInt(params.editor.inactiveValue ?? '0') |
|||
// } |
|||
// |
|||
// } else if (convType === 'str') { |
|||
// if (boolValue) { |
|||
// newValue = params.editor.activeValue |
|||
// } else { |
|||
// newValue = params.editor.inactiveValue |
|||
// } |
|||
// } |
|||
// |
|||
// const dataIndex = props.params.colDef?.field || '' |
|||
// |
|||
// if (dataIndex.includes('.')) { |
|||
// _.set(props.params.data, dataIndex, newValue) |
|||
// } else { |
|||
// params.node.data[params.colDef.field] = newValue |
|||
// } |
|||
// |
|||
// const yvAggrid = props.params.context.componentParent |
|||
// yvAggrid.onCellValueChanged({ |
|||
// ...params, |
|||
// value: newValue, |
|||
// valueFormatted: `${newValue}` |
|||
// }) |
|||
// } |
|||
// |
|||
// onMounted(() => { |
|||
// nextTick(() => { |
|||
// data.isActive = true |
|||
// }) |
|||
// let value = props.params.value |
|||
// data.boolValue = false |
|||
// |
|||
// const convType = props.params.editor?.convType ?? 'bool' |
|||
// |
|||
// if (convType === 'bool') { |
|||
// if (`${value}` === 'true') { |
|||
// data.boolValue = true |
|||
// } |
|||
// |
|||
// } else { |
|||
// if (props.params.editor.activeValue) { |
|||
// if (`${value}` === props.params.editor.activeValue) { |
|||
// } |
|||
// data.boolValue = true |
|||
// } else { |
|||
// // 没有激活值 |
|||
// if (`${value}` === '1' || `${value}` === 'true' || `${value}` === 'Y') { |
|||
// data.boolValue = true |
|||
// } |
|||
// } |
|||
// } |
|||
// |
|||
// // if (this.boolValue === false) { |
|||
// // console.log('boolValue=false and params.value=' + value) |
|||
// // } |
|||
// }) |
|||
// |
|||
// return { |
|||
// data, |
|||
// getValue, |
|||
// onChange, |
|||
// onBeforeChange |
|||
// } |
|||
// } |
|||
// }) |
|||
|
|||
// const props = defineProps({ |
|||
// params: Object, |
|||
// value: null, |
|||
// }) |
|||
// |
|||
// debugger |
|||
|
|||
</script> |
|||
@ -0,0 +1,154 @@ |
|||
<template> |
|||
<el-select ref="_inner" v-model="value" :multiple="multiple" :allow-create="allowCreate" |
|||
filterable clearable class="yv-inner-aggrid-combo" |
|||
placement="bottom-start" |
|||
:fallback-placements="['bottom-start', 'top-start']" |
|||
@keyup="onEscKeyDown" |
|||
@change="onChange"> |
|||
<el-option v-for="option in options" |
|||
:key="option.value" |
|||
:label="option.label" |
|||
:value="option.value" |
|||
/> |
|||
</el-select> |
|||
</template> |
|||
<script> |
|||
import _ from 'lodash' |
|||
import {defineComponent, nextTick, computed, reactive, defineProps, watch, onMounted, ref} from "vue" |
|||
import {ElSelect} from 'element-plus' |
|||
|
|||
export default { |
|||
props: ['params'], |
|||
components: {ElSelect}, |
|||
mounted() { |
|||
this.value = this.params.value; |
|||
nextTick(() => { |
|||
this.$refs._inner?.focus() |
|||
this.$refs._inner?.toggleMenu() |
|||
}) |
|||
}, |
|||
data() { |
|||
return { |
|||
value: null, |
|||
} |
|||
}, |
|||
computed: { |
|||
allowCreate() { |
|||
return (this.params.editor.allowCreate === true) |
|||
}, |
|||
multiple() { |
|||
return (this.params.editor.multiple === true) |
|||
}, |
|||
options() { |
|||
if (typeof this.params.editor.options === 'function') { |
|||
return this.params.editor.options() |
|||
} |
|||
if (typeof this.params.editor.options === 'object' && |
|||
typeof this.params.editor.options.scope === 'function' && |
|||
typeof this.params.editor.options.method === 'string') { |
|||
const opt = this.params.editor.options |
|||
return opt.scope()[opt.method] |
|||
} |
|||
return this.params.editor.options |
|||
} |
|||
}, |
|||
watch: { |
|||
value(newVal) { |
|||
const dataIndex = this.params.colDef?.field || '' |
|||
if (dataIndex.includes('.')) { |
|||
// const nodeData = this.params.node.data |
|||
// _.set(nodeData, dataIndex, newVal) |
|||
this.params.onCellValueChanged({ |
|||
...this.params, |
|||
newValue: newVal, |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
onEscKeyDown(evt) { |
|||
if (evt.code === 'Escape') { |
|||
// 停止编辑 |
|||
this.params.stopEditing() |
|||
} |
|||
}, |
|||
getValue() { |
|||
return this.value; |
|||
}, |
|||
onChange(newValue) { |
|||
} |
|||
} |
|||
} |
|||
|
|||
// export default defineComponent({ |
|||
// name: "YvAggridCheckbox", |
|||
// components: {ElSelect}, |
|||
// props: ['value', 'params'], |
|||
// setup(props) { |
|||
// const _inner = ref(null) |
|||
// const data = reactive({ |
|||
// value: null, |
|||
// }) |
|||
// |
|||
// function getValue() { |
|||
// return props.value; |
|||
// } |
|||
// |
|||
// function onChange(newValue) { |
|||
// } |
|||
// |
|||
// const allowCreate = computed(() => { |
|||
// return (props.params.editor.allowCreate === true) |
|||
// }) |
|||
// const multiple = computed(() => { |
|||
// return (props.params.editor.multiple === true) |
|||
// }) |
|||
// const options = computed(() => { |
|||
// if (typeof props.params.editor.options === 'function') { |
|||
// return props.params.editor.options() |
|||
// } |
|||
// return props.params.editor.options |
|||
// }) |
|||
// |
|||
// watch(() => props.value, (newVal) => { |
|||
// const dataIndex = props.params.colDef?.field || '' |
|||
// |
|||
// if (dataIndex.includes('.')) { |
|||
// _.set(props.params.data, dataIndex, newVal) |
|||
// } |
|||
// }) |
|||
// |
|||
// onMounted(() => { |
|||
// data.value = props.params.value; |
|||
// nextTick(() => { |
|||
// _inner.value?.focus() |
|||
// }) |
|||
// }) |
|||
// |
|||
// return { |
|||
// _inner, |
|||
// data, options, |
|||
// getValue, |
|||
// onChange, |
|||
// allowCreate, |
|||
// multiple, |
|||
// } |
|||
// } |
|||
// }) |
|||
|
|||
// const props = defineProps({ |
|||
// params: Object, |
|||
// value: null, |
|||
// }) |
|||
// debugger |
|||
|
|||
</script> |
|||
<style> |
|||
.yv-inner-aggrid-combo { |
|||
width: 100%; |
|||
} |
|||
|
|||
.yv-inner-aggrid-combo.el-select .el-input.is-focus .el-input__wrapper { |
|||
box-shadow: none !important; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,105 @@ |
|||
<template> |
|||
<slot /> |
|||
<div v-element-dialog-resize="{ draggable: true, fullscreen: true }"> |
|||
<el-dialog v-model="showCodeWindow" :title="title" width="80%" |
|||
class="resize-dialog" |
|||
append-to-body |
|||
:close-on-press-escape="true" |
|||
:close-on-click-modal="false" |
|||
style="padding:0;height: 400px;" |
|||
@opened="onWindowOpen"> |
|||
<YvJsonEditor language="json" v-model="code" /> |
|||
<template #footer> |
|||
<el-button type="danger" :icon="renderIcon('Save')" @click="importCommit">确定</el-button> |
|||
<el-button :icon="renderIcon('Times')" @click="()=>this.showCodeWindow=false">关闭</el-button> |
|||
</template> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import _ from 'lodash' |
|||
import YvJsonEditor from '../YvJsonEditor.vue' |
|||
import { renderIcon } from '@/utils/webutils.js' |
|||
import ElementDialogResize from '@/components/element-dialog-resize' |
|||
|
|||
export default { |
|||
directives: { ElementDialogResize }, |
|||
props: { |
|||
modelValue: Object, |
|||
title: { type: String, default: '代码编辑', required: false }, |
|||
mergeOnly: { type: Boolean, default: true, required: false }, |
|||
mergeCode: { type: Function, required: false }, |
|||
toJsonStr: { type: Function, required: false }, |
|||
isFreeze: { type: Boolean, default: false, required: false } |
|||
}, |
|||
components: { YvJsonEditor }, |
|||
emits: ['codeCommit', 'update:modelValue'], |
|||
data() { |
|||
return { |
|||
showCodeWindow: false, |
|||
code: '' |
|||
} |
|||
}, |
|||
watch: { |
|||
'modelValue': { |
|||
handler(newVal) { |
|||
if (this.showCodeWindow) { |
|||
this.code = JSON.stringify(newVal, null, 2) |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
renderIcon, |
|||
show() { |
|||
this.showCodeWindow = true |
|||
}, |
|||
onWindowOpen() { |
|||
if (typeof this.toJsonStr === 'function') { |
|||
const code = this.toJsonStr(this.modelValue) |
|||
if (typeof code === 'string') { |
|||
this.code = code |
|||
} else { |
|||
this.code = JSON.stringify(code, null, 2) |
|||
} |
|||
return |
|||
} |
|||
this.code = JSON.stringify(this.modelValue, null, 2) |
|||
}, |
|||
importCommit() { |
|||
try { |
|||
let targetObject = JSON.parse(this.code) |
|||
this.showCodeWindow = false |
|||
|
|||
if (typeof this.mergeCode === 'function') { |
|||
this.mergeCode(this.modelValue, targetObject) |
|||
this.$emit('codeCommit', this.modelValue) |
|||
|
|||
} else { |
|||
if (this.mergeOnly) { |
|||
// 合并到新属性中 |
|||
Object.keys(this.modelValue).forEach(key => { |
|||
if (!targetObject.hasOwnProperty(key)) { |
|||
delete this.modelValue[key] |
|||
} |
|||
}) |
|||
|
|||
_.assign(this.modelValue, targetObject) |
|||
this.$emit('codeCommit', this.modelValue) |
|||
|
|||
} else { |
|||
if (this.isFreeze) { |
|||
targetObject = Object.freeze(targetObject) |
|||
} |
|||
this.$emit('update:modelValue', targetObject) |
|||
this.$emit('codeCommit', targetObject) |
|||
} |
|||
} |
|||
|
|||
} catch (e) { |
|||
system.showErrorDialog('保存出错:', e.toString()) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,808 @@ |
|||
<template> |
|||
<div class="yv-table-wrap"> |
|||
<el-row v-if="setting.showToolbar"> |
|||
<slot name="toolbar" /> |
|||
<el-dropdown v-if="!setting.disableAppendButton" |
|||
split-button type="primary" :icon="renderIcon('Plus')" @click="()=>appendRow({})" |
|||
class="is-link" trigger="click"> |
|||
<component :is="renderIcon('Plus')" /> |
|||
新增 |
|||
<template #dropdown> |
|||
<el-dropdown-menu> |
|||
<el-dropdown-item @click="_appendNewNumClick"> |
|||
添加 |
|||
<el-input-number v-model="appendNewNum" :min="1" :max="999" size="small" @click.stop="()=>{}" |
|||
@keydown.enter="_appendNewNumClick" |
|||
style="width:80px;margin:0 5px" /> |
|||
行 |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</template> |
|||
</el-dropdown> |
|||
|
|||
<el-button type="warning" link :icon="renderIcon('Delete')" @click="removeSelectedRows" |
|||
v-if="!setting.disableDeleteButton" |
|||
>删除 |
|||
</el-button> |
|||
<YvJsonCode :modelValue="modelValue" :to-json-str="removeRidHandle" :merge-code="createRidHandle" |
|||
ref="arrayCodeDesign"> |
|||
<el-button link :icon="renderIcon('Code')" @click="()=>$refs.arrayCodeDesign.show()">编辑JSON</el-button> |
|||
</YvJsonCode> |
|||
<el-input placeholder="筛选" v-model="filterStr" style="margin-left: 5px;width:200px;" size="small" clearable /> |
|||
|
|||
</el-row> |
|||
<ag-grid-vue |
|||
v-if="!!gridOption" |
|||
:class="['ag-theme-alpine', 'yv-table', 'hi-light-selected-row','allow-vertical-line']" |
|||
ref="_inner" |
|||
v-bind="gridOption" |
|||
:getRowId="getRowId" |
|||
:columnDefs="columnDefs" |
|||
@gridReady="onReady" |
|||
@cell-clicked="onCellClicked" |
|||
@cellEditingStarted="onCellEditingStarted" |
|||
@cellEditingStopped="onCellEditingStopped" |
|||
@cellDoubleClicked="onCellDoubleClicked" |
|||
@rowClicked="onRowClick" |
|||
@selectionChanged="onSelectionChange" |
|||
@rowDoubleClicked="onRowDblClick" |
|||
@rowDataUpdated="onRowDataUpdated" |
|||
@rowDragEnd="onRowDragEnd" |
|||
@cellValueChanged="onCellValueChanged" |
|||
/> |
|||
<slot /> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import _ from 'lodash' |
|||
import { markRaw, toRaw } from 'vue' |
|||
import { renderIcon } from '@/utils/webutils.js' |
|||
import { localeText as localeTextCn } from './yv-aggrid-cn.locale' |
|||
import { localeText as localeTextEn } from './yv-aggrid-en.locale' |
|||
import YvAggridCheckbox from './YvAggridCheckbox.vue' |
|||
import YvAggridCombo from './YvAggridCombo.vue' |
|||
import DeleteCellRenderer from './DeleteCellRenderer.vue' |
|||
import YvJsonCode from './YvJsonCode.vue' |
|||
|
|||
import 'ag-grid-community/styles/ag-grid.css' |
|||
import 'ag-grid-community/styles/ag-theme-alpine.css' |
|||
|
|||
const GridRowHeight = 32 |
|||
|
|||
export default { |
|||
components: { |
|||
YvJsonCode, |
|||
YvAggridCheckbox, YvAggridCombo, DeleteCellRenderer |
|||
}, |
|||
props: { |
|||
setting: { type: Object, required: true }, |
|||
modelValue: { type: Array, required: false }, |
|||
selectedRow: { type: Object, required: false, default: undefined } |
|||
}, |
|||
emits: [ |
|||
'actionClick', |
|||
'selectionChange', |
|||
'onReady', |
|||
'isChanged', |
|||
'rowDblClick', |
|||
'rowClick', |
|||
'rowDataUpdated', |
|||
'rowDragEnd', |
|||
'cellClicked', |
|||
'cellEditingStarted', |
|||
'cellEditingStopped', |
|||
'cellDoubleClicked', |
|||
'update:modelValue', |
|||
'update:selectedRow', |
|||
'update:selectedRows' |
|||
], |
|||
data() { |
|||
const gridOption = this.buildGridOption(this.setting) |
|||
const columnDefs = gridOption.columnDefs |
|||
|
|||
return { |
|||
api: null, |
|||
columnApi: null, |
|||
filterStr: '', |
|||
isChanged: false, |
|||
gridOption: Object.freeze(gridOption), |
|||
columnDefs: Object.freeze(columnDefs), |
|||
appendNewNum: 10, |
|||
insertBeforeNewNum: 1, |
|||
insertAfterNewNum: 1 |
|||
} |
|||
}, |
|||
mounted() { |
|||
window['pp'] = this |
|||
}, |
|||
watch: { |
|||
filterStr: { |
|||
handler(newValue) { |
|||
this.api.setQuickFilter(newValue) |
|||
} |
|||
}, |
|||
modelValue: { |
|||
deep: true, |
|||
handler(newValue) { |
|||
// console.log('watch modelValue changed') |
|||
this.syncData() |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
renderIcon, |
|||
onActionClick(action, params) { |
|||
const modelRow = _.find(this.modelValue, (row) => row._rid === params.data._rid) |
|||
this.$emit('actionClick', action, params, modelRow) |
|||
}, |
|||
removeRidHandle(newArray) { |
|||
if (!_.isArray(newArray)) { |
|||
return [] |
|||
} |
|||
return newArray.map(item => { |
|||
const newItem = _.cloneDeep(item) |
|||
delete newItem._rid |
|||
return newItem |
|||
}) |
|||
}, |
|||
createRidHandle(currentArray, newArray) { |
|||
if (!_.isArray(newArray)) { |
|||
throw new Error('newArray is not array') |
|||
} |
|||
for (let i = 0; i < newArray.length; i++) { |
|||
newArray[i]._rid = _.uniqueId('_') |
|||
} |
|||
this.$emit('update:modelValue', newArray) |
|||
}, |
|||
getRowId(params) { |
|||
return params.data._rid |
|||
}, |
|||
filter(str) { |
|||
this.api.setQuickFilter(str) |
|||
}, |
|||
/** |
|||
* 停止编辑 |
|||
*/ |
|||
stopEditing() { |
|||
this.api.stopEditing() |
|||
}, |
|||
/** |
|||
* 获取全部数据行, 每个行都会附带 _rid 属性, 用于标识这一行的数据 |
|||
* @returns {Array} 数据行的数组 |
|||
*/ |
|||
getDataRows() { |
|||
this.stopEditing() |
|||
|
|||
const rows = [] |
|||
this.api.forEachNode((node) => { |
|||
if (!node.data) { |
|||
return |
|||
} |
|||
rows.push(node.data) |
|||
}) |
|||
return rows |
|||
}, |
|||
printNode() { |
|||
this.stopEditing() |
|||
|
|||
const rows = [] |
|||
this.api.forEachNode((node) => { |
|||
rows.push(node) |
|||
}) |
|||
return rows |
|||
}, |
|||
getNodeByRowIndex(rowIndex) { |
|||
this.stopEditing() |
|||
|
|||
let ret = undefined |
|||
this.api.forEachNode((node) => { |
|||
if (node.rowIndex === rowIndex) { |
|||
ret = node |
|||
return false |
|||
} |
|||
}) |
|||
return ret |
|||
}, |
|||
/** |
|||
* 获取所有选中行,返回的数据中包含 _rid 字段. |
|||
* _rid 字段可以作为 setRowDataByRowid / removeRowByRowid 的参数 |
|||
*/ |
|||
getSelectedRows() { |
|||
if (!this.api) { |
|||
return [] |
|||
} |
|||
this.stopEditing() |
|||
|
|||
const sel = [] |
|||
// 从 selected 中获取选中行 |
|||
this.api.forEachNode((node) => { |
|||
if (node.selected && node.displayed) { |
|||
if (node.data?._rid) { |
|||
const modelRow = _.find(this.modelValue, (row) => row._rid === node.data._rid) |
|||
if (modelRow) { |
|||
sel.push(modelRow) |
|||
} |
|||
} |
|||
} |
|||
}) |
|||
|
|||
if (sel.length <= 0) { |
|||
// 如果一个都没有获取,从 range 中获取 |
|||
const ridList = [] |
|||
_.forEach(this.api.getCellRanges(), range => { |
|||
const startRow = range.startRow.rowIndex > range.endRow.rowIndex ? range.endRow.rowIndex : range.startRow.rowIndex |
|||
const endRow = range.startRow.rowIndex > range.endRow.rowIndex ? range.startRow.rowIndex : range.endRow.rowIndex |
|||
for (let i = startRow; i <= endRow; i++) { |
|||
const row = this.api.getDisplayedRowAtIndex(i) |
|||
if (row.data?._rid && !ridList.includes(row.data._rid)) { |
|||
ridList.push(row.data._rid) |
|||
} |
|||
} |
|||
}) |
|||
|
|||
_.forEach(ridList, (rid) => { |
|||
const row = _.find(this.modelValue, (row) => row._rid === rid) |
|||
if (row) { |
|||
sel.push(row) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
return sel |
|||
}, |
|||
/** |
|||
* 通过 _rid 计算变化的数据并同步到表格 |
|||
*/ |
|||
syncData() { |
|||
if (!_.isArray(this.modelValue)) { |
|||
console.log('applyTransaction', []) |
|||
this.api?.setRowData([]) |
|||
return |
|||
} |
|||
|
|||
// 比较 modelValue 和 aggrid 的差异, 仅更新有变化的行 |
|||
const sel = { |
|||
add: [], |
|||
update: [], |
|||
remove: [] |
|||
} |
|||
const modelValue = this.modelValue |
|||
const insertRows = [...modelValue] |
|||
this.api?.forEachNode((node) => { |
|||
if (!node.data) { |
|||
return |
|||
} |
|||
|
|||
const modelRow = _.find(modelValue, (row) => node.data._rid === row._rid) |
|||
_.remove(insertRows, r => r === modelRow) |
|||
if (!modelRow) { |
|||
// 被删除的行 |
|||
sel.remove.push(node.data) |
|||
|
|||
} else if (!_.isEqual(node.data, modelRow)) { |
|||
// 有变化的行 |
|||
Object.assign(node.data, _.cloneDeep(modelRow)) |
|||
sel.update.push(node.data) |
|||
} |
|||
}) |
|||
|
|||
_.forEach(insertRows, (row, index) => { |
|||
if (!row._rid) { |
|||
row._rid = _.uniqueId('_') |
|||
} |
|||
}) |
|||
sel.add = _.cloneDeep(insertRows) |
|||
if (sel.add.length > 0 || sel.update.length > 0 || sel.remove.length > 0) { |
|||
console.log('applyTransaction', sel) |
|||
this.api?.applyTransaction(sel) |
|||
this.refreshRowCount() |
|||
} |
|||
}, |
|||
/** |
|||
* 最强制的方法刷新数据 |
|||
*/ |
|||
refreshData() { |
|||
if (!this.modelValue) { |
|||
this.api?.setRowData([]) |
|||
return |
|||
} |
|||
|
|||
// 为 modelValue 每一行加一个 _rid |
|||
_.forEach(this.modelValue, (row, index) => { |
|||
row._rid = _.uniqueId('_') |
|||
}) |
|||
|
|||
this.api?.setRowData(_.cloneDeep(this.modelValue)) |
|||
this.refreshRowCount() |
|||
}, |
|||
appendRow(row) { |
|||
if (!_.isArray(this.modelValue)) { |
|||
if (_.isArray(row)) { |
|||
this.$emit('update:modelValue', [...row]) |
|||
} else { |
|||
this.$emit('update:modelValue', [row]) |
|||
} |
|||
|
|||
} else { |
|||
if (_.isArray(row)) { |
|||
this.modelValue.push(...row) |
|||
|
|||
} else { |
|||
this.modelValue.push(row) |
|||
} |
|||
} |
|||
}, |
|||
/** |
|||
* 删除单元格模式下选中的行 |
|||
*/ |
|||
removeSelectedRows() { |
|||
const rows = this.getSelectedRows() |
|||
if (rows.length <= 0) { |
|||
system.msg('请选择要删除的行') |
|||
return |
|||
} |
|||
|
|||
system.confirm('确定要删除选中的' + rows.length + '行吗?').then(() => { |
|||
const deleted = _.remove(this.modelValue, (r) => _.includes(rows, r)) |
|||
if (deleted.length > 0) { |
|||
system.msg('成功删除' + deleted.length + '行') |
|||
this.api.clearRangeSelection() |
|||
} else { |
|||
system.msg('没有删除任何行') |
|||
} |
|||
}) |
|||
}, |
|||
buildGridOption() { |
|||
let localeText |
|||
// if (this.locale?.name === 'zh-cn') { |
|||
localeText = localeTextCn |
|||
// } else { |
|||
// localeText = localeTextEn |
|||
// } |
|||
const setting = _.cloneDeep(this.setting) |
|||
|
|||
const gridOption = { |
|||
localeText: localeText, |
|||
context: { |
|||
componentParent: this |
|||
}, |
|||
columnDefs: this.processColumns(setting), |
|||
suppressPropertyNamesCheck: true, |
|||
suppressMaxRenderedRowRestriction: true, |
|||
animateRows: false, |
|||
suppressContextMenu: true, |
|||
suppressAggFuncInHeader: true, |
|||
enableCellTextSelection: true, |
|||
ensureDomOrder: true, |
|||
domLayout: setting.domLayout, |
|||
tooltipInteraction: true, |
|||
suppressScrollOnNewData: true, |
|||
popupParent: document.querySelector('body'), |
|||
rowHeight: GridRowHeight, |
|||
defaultColDef: { |
|||
editable: false, |
|||
singleClickEdit: false, |
|||
sortable: true, |
|||
serverSortable: true, |
|||
resizable: true, |
|||
enableRowGroup: true, |
|||
enablePivot: true, |
|||
enableValue: true, |
|||
filter: true |
|||
} |
|||
} |
|||
|
|||
if (setting.showDeleteButton) { |
|||
gridOption.columnDefs.push({ |
|||
headerName: '操作', |
|||
width: 60, |
|||
maxWidth: 60, |
|||
minWidth: 60, |
|||
suppressMenu: true, |
|||
suppressSizeToFit: true, |
|||
suppressAutoSize: true, |
|||
suppressMovable: true, |
|||
suppressColumnsToolPanel: true, |
|||
pinned: 'right', |
|||
cellRenderer: 'DeleteCellRenderer' |
|||
}) |
|||
} |
|||
|
|||
if (setting.mode === 'select') { |
|||
// 单行选择 |
|||
_.extend(gridOption, { |
|||
rowSelection: 'single', |
|||
checkboxSelection: false, |
|||
enableRangeSelection: false, |
|||
suppressCellFocus: true, |
|||
enableCellTextSelection: true, |
|||
ensureDomOrder: true |
|||
}) |
|||
gridOption.defaultColDef.singleClickEdit = false |
|||
gridOption.defaultColDef.editable = false |
|||
|
|||
} else if (setting.mode === 'edit1') { |
|||
// 单击编辑 |
|||
_.extend(gridOption, { |
|||
// rowSelection: 'single', |
|||
enableCellTextSelection: false, |
|||
ensureDomOrder: false, |
|||
enableRangeSelection: true, |
|||
suppressContextMenu: false |
|||
}) |
|||
gridOption.defaultColDef.singleClickEdit = true |
|||
|
|||
} else if (setting.mode === 'edit2') { |
|||
// 双击编辑 |
|||
_.extend(gridOption, { |
|||
// rowSelection: 'multiple', |
|||
enableCellTextSelection: false, |
|||
ensureDomOrder: false, |
|||
enableRangeSelection: true, |
|||
suppressContextMenu: false |
|||
}) |
|||
gridOption.defaultColDef.singleClickEdit = false |
|||
|
|||
} else if (setting.mode === 'checkbox') { |
|||
|
|||
_.extend(gridOption, { |
|||
rowSelection: 'multiple', |
|||
checkboxSelection: true, |
|||
enableCellTextSelection: true, |
|||
ensureDomOrder: true |
|||
}) |
|||
} |
|||
|
|||
if (setting.rowDragable) { |
|||
gridOption.animateRows = true |
|||
gridOption.rowDragManaged = true |
|||
} |
|||
|
|||
return gridOption |
|||
}, |
|||
processColumns(setting) { |
|||
const me = this |
|||
const list = [] |
|||
|
|||
_.forEach(setting.columns, column => { |
|||
|
|||
if (typeof column.action === 'string') { |
|||
const action = column.action |
|||
delete column.action |
|||
_.assign(column, { |
|||
headerName: '操作', |
|||
suppressMenu: true, |
|||
suppressSizeToFit: true, |
|||
suppressAutoSize: true, |
|||
suppressMovable: true, |
|||
suppressColumnsToolPanel: true, |
|||
cellRenderer: 'DeleteCellRenderer', |
|||
cellRendererParams: { |
|||
action: action, |
|||
columnVjson: column.vjsonRaw, |
|||
scope: () => this.vcxt.scope, |
|||
vcxt: () => this.vcxt, |
|||
instance: () => this |
|||
} |
|||
}) |
|||
} |
|||
|
|||
if (column.dataIndex) { |
|||
column.field = column.dataIndex |
|||
delete column.dataIndex |
|||
} |
|||
|
|||
if (column.header) { |
|||
column.headerName = column.header |
|||
delete column.header |
|||
} |
|||
|
|||
if (typeof column.resizable === 'undefined') { |
|||
column.resizable = true |
|||
} |
|||
|
|||
if (typeof column.hidden !== 'undefined') { |
|||
column.hide = column.hidden |
|||
delete column.hidden |
|||
} |
|||
|
|||
if (setting.disableColumnMenu === true && typeof column.suppressMenu === 'undefined') { |
|||
column.suppressMenu = true |
|||
} |
|||
if (setting.sortable === false && typeof column.sortable === 'undefined') { |
|||
column.sortable = false |
|||
} |
|||
|
|||
if (column.editor) { |
|||
const editor = column.editor |
|||
delete column.editor |
|||
|
|||
if (editor.xtype === 'checkbox') { |
|||
_.extend(column, { |
|||
editable: true, |
|||
// cellEditor: 'YvAggridCheckbox', |
|||
// editable: false, |
|||
// cellRendererFramework: 'YvAggridCheckbox', |
|||
cellRenderer: 'YvAggridCheckbox', |
|||
cellRendererParams: { |
|||
editor: editor, |
|||
setEditRow: this.setEditRow, |
|||
top: this |
|||
} |
|||
}) |
|||
} else if (editor.xtype === 'combo') { |
|||
_.extend(column, { |
|||
cellEditor: 'YvAggridCombo', |
|||
cellEditorParams: { |
|||
onCellValueChanged: this.onCellValueChanged.bind(this), |
|||
editor: editor, |
|||
top: () => this |
|||
} |
|||
// valueFormatter(param) { |
|||
// if (typeof param.value === 'undefined') { |
|||
// return '' |
|||
// } |
|||
// |
|||
// let dictArray = editor.options |
|||
// if (typeof dictArray === 'function') { |
|||
// dictArray = dictArray() |
|||
// } else if (typeof dictArray === 'object' && typeof dictArray.scope === 'function' && typeof dictArray.method === 'string') { |
|||
// dictArray = editor.options.scope()[editor.options.method] |
|||
// me.$watch(() => editor.options.scope()[editor.options.method], () => { |
|||
// me.api.refreshCells() |
|||
// }) |
|||
// } |
|||
// const dictItem = _.find(dictArray, (dictItem) => (('' + dictItem.value) === ('' + param.value))) |
|||
// if (!dictItem) { |
|||
// return param.value |
|||
// } |
|||
// |
|||
// return dictItem.label |
|||
// } |
|||
}) |
|||
|
|||
} else { |
|||
throw new Error('不支持的编辑器类型:' + editor.xtype) |
|||
} |
|||
} |
|||
|
|||
list.push(column) |
|||
}) |
|||
|
|||
if (setting.mode === 'checkbox') { |
|||
list.splice(0, 0, { |
|||
width: 37, |
|||
resizable: false, |
|||
suppressMenu: true, |
|||
headerCheckboxSelection: true, |
|||
enableCellTextSelection: true, |
|||
checkboxSelection: true, |
|||
suppressMovable: true, |
|||
suppressSizeToFit: true, |
|||
suppressAutoSize: true, |
|||
sortable: false, |
|||
serverSortable: false, |
|||
pinned: 'left' |
|||
}) |
|||
} |
|||
|
|||
if (setting.rowDragable) { |
|||
list.splice(0, 0, { |
|||
width: 25, |
|||
resizable: false, |
|||
suppressMenu: true, |
|||
rowDrag: true |
|||
}) |
|||
} |
|||
|
|||
if (setting.rowNumber) { |
|||
const hashValueGetter = (params) => { |
|||
return params.node ? (params.node.rowIndex + 1) : null |
|||
} |
|||
list.splice(0, 0, { |
|||
headerName: '#', |
|||
width: 30, |
|||
maxWidth: 100, |
|||
filter: false, |
|||
editable: false, |
|||
pinned: 'left', |
|||
resizable: true, |
|||
sortable: false, |
|||
serverSortable: false, |
|||
enableRowGroup: false, |
|||
enablePivot: false, |
|||
suppressMenu: true, |
|||
suppressColumnsToolPanel: true, |
|||
valueGetter: hashValueGetter |
|||
}) |
|||
} |
|||
|
|||
return list |
|||
}, |
|||
runEvent(name, ...params) { |
|||
this.$emit(name, ...params) |
|||
}, |
|||
onReady(evt) { |
|||
this.api = markRaw(evt.api) |
|||
this.columnApi = markRaw(evt.columnApi) |
|||
this.refreshData() |
|||
this.isChanged = false |
|||
this.runEvent('onReady') |
|||
}, |
|||
onCellClicked() { |
|||
this.$emit('cellClicked', ...arguments) |
|||
}, |
|||
onCellEditingStarted(param) { |
|||
if (param.colDef.cellRenderer === 'YvAggridCheckbox') { |
|||
this.stopEditing() |
|||
} |
|||
this.$emit('cellEditingStarted', ...arguments) |
|||
}, |
|||
onCellEditingStopped() { |
|||
this.$emit('cellEditingStopped', ...arguments) |
|||
}, |
|||
onCellDoubleClicked() { |
|||
this.$emit('cellDoubleClicked', ...arguments) |
|||
}, |
|||
onRowClick() { |
|||
this.$emit('rowClick', ...arguments) |
|||
}, |
|||
onSelectionChange({ api }) { |
|||
if (!api) { |
|||
return |
|||
} |
|||
const rows = api.getSelectedNodes() |
|||
this.$nextTick(() => { |
|||
this.$emit('update:selectedRow', rows[0]) |
|||
this.$emit('update:selectedRows', rows) |
|||
}) |
|||
}, |
|||
onRowDblClick() { |
|||
this.$emit('rowDblClick', ...arguments) |
|||
}, |
|||
onRowDragEnd(param) { |
|||
this.$emit('update:modelValue', this.getDataRows()) |
|||
this.$emit('rowDragEnd', param) |
|||
}, |
|||
onCellValueChanged(param) { |
|||
let { data, colDef, newValue } = param |
|||
if (!colDef) { |
|||
return |
|||
} |
|||
// 如果是 checkbox 类型,需要转换字符串到布尔 |
|||
if (colDef.cellRenderer === 'YvAggridCheckbox' && |
|||
colDef.cellRendererParams.editor?.convType !== 'num' && |
|||
colDef.cellRendererParams.editor?.convType !== 'str') { |
|||
if (newValue === 'true') { |
|||
newValue = true |
|||
} else if (newValue === 'false') { |
|||
newValue = false |
|||
} |
|||
} |
|||
|
|||
if (!data._rid) { |
|||
system.showErrorDialog('数据行没有 _rid 属性') |
|||
} |
|||
const modelRow = _.find(this.modelValue, (row) => (row._rid === data._rid)) |
|||
if (!modelRow) { |
|||
system.showErrorDialog('数据行没有找到') |
|||
} |
|||
const dataIndex = colDef?.field || '' |
|||
if (dataIndex.includes('.')) { |
|||
if (Object.hasOwn(modelRow, dataIndex)) { |
|||
// 这是一个 bug ,将路径名变成了属性名 |
|||
delete modelRow[dataIndex] |
|||
} |
|||
_.set(modelRow, colDef.field, newValue) |
|||
|
|||
} else { |
|||
modelRow[dataIndex] = newValue |
|||
} |
|||
|
|||
}, |
|||
onRowDataUpdated(param) { |
|||
// console.log('rowDataUpdated', param.type) |
|||
// this.$emit('rowDataUpdated', param) |
|||
}, |
|||
refreshRowCount() { |
|||
this.onSelectionChange({ api: this.api }) |
|||
}, |
|||
setData() { |
|||
if (!this.api) { |
|||
return |
|||
} |
|||
this.api.setRowData(this.modelValue) |
|||
this.refreshRowCount() |
|||
}, |
|||
setEditRow(rowData) { |
|||
// 找到正在编辑的单元格 |
|||
const [cell] = this.api.getEditingCells() |
|||
if (!cell) { |
|||
return |
|||
} |
|||
|
|||
// 找到这一行所属的 node |
|||
let node |
|||
this.api.forEachNode((item) => { |
|||
if (!item.data) { |
|||
return |
|||
} |
|||
if (item.rowIndex === cell.rowIndex) { |
|||
node = item |
|||
return false |
|||
} |
|||
}) |
|||
|
|||
// 将 rowData 中除 _ 开头的所有数据设置给 nodeData |
|||
const nodeData = _.cloneDeep(node.data) |
|||
_.forOwn(rowData, (value, key) => { |
|||
if (key.startsWith('_')) { |
|||
return |
|||
} |
|||
_.set(nodeData, key, value) |
|||
}) |
|||
nodeData['_rid'] = node.id |
|||
// console.log("setSelectionRow", nodeData) |
|||
node.setData(nodeData) |
|||
|
|||
this.runEvent('isChanged', true) |
|||
|
|||
// 拿到正在编辑的编辑器, 变更编辑器里面的值 |
|||
const colId = cell.column.colId |
|||
if (colId && Object.hasOwn(rowData, colId)) { |
|||
const [editor] = this.api.getCellEditorInstances() |
|||
editor.value = rowData[colId] |
|||
} |
|||
}, |
|||
/** |
|||
* 设置表格的 loading 读取状态 |
|||
* @param isLoad 是否"载入中" |
|||
*/ |
|||
setLoading(isLoad) { |
|||
if (this.api) { |
|||
if (isLoad === true) { |
|||
this.api.showLoadingOverlay() |
|||
} else { |
|||
this.api.hideOverlay() |
|||
} |
|||
} |
|||
}, |
|||
_appendNewNumClick() { |
|||
const rowNum = parseInt(this.appendNewNum) |
|||
if (rowNum > 0) { |
|||
const list = [] |
|||
for (let i = 0; i < rowNum; i++) { |
|||
list.push({}) |
|||
} |
|||
this.appendRow(list) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
<style lang="less"> |
|||
|
|||
.yv-table-wrap { |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
|
|||
& > .yv-table { |
|||
flex-grow: 1; |
|||
display: flex; |
|||
|
|||
&.allow-vertical-line .ag-cell-value { |
|||
border-right: 1px solid #ebeef5; |
|||
// border-right: 1px solid rgba(0, 0, 0, 0.09); |
|||
} |
|||
|
|||
& > .ag-root-wrapper { |
|||
flex-grow: 1; |
|||
} |
|||
|
|||
&.hi-light-selected-row .ag-row-focus { |
|||
background: var(--el-color-primary-light-8); |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,69 @@ |
|||
export const localeText = { |
|||
page: "页", |
|||
more: "更多", |
|||
to: "到", |
|||
of: "of", |
|||
next: "下⼀页", |
|||
last: "上⼀页", |
|||
first: "⾸页", |
|||
previous: "上⼀页", |
|||
loadingOoo: "加载中...", |
|||
selectAll: "查询全部", |
|||
searchOoo: "查询...", |
|||
blanks: "空⽩", |
|||
filterOoo: "过滤...", |
|||
applyFilter: "保存过滤器...", |
|||
equals: "相等", |
|||
notEqual: "不相等", |
|||
lessThan: "⼩于", |
|||
greaterThan: "⼤于", |
|||
lessThanOrEqual: "⼩于等于", |
|||
greaterThanOrEqual: "⼤于等于", |
|||
inRange: "范围", |
|||
contains: "包含", |
|||
notContains: "不包含", |
|||
startsWith: "开始于", |
|||
endsWith: "结束于", |
|||
group: "组", |
|||
columns: "列", |
|||
filters: "筛选", |
|||
rowGroupColumns: "laPivot Cols", |
|||
rowGroupColumnsEmptyMessage: "la drag cols to group", |
|||
valueColumns: "laValue Cols", |
|||
pivotMode: "laPivot-Mode", |
|||
groups: "laGroups", |
|||
values: "值", |
|||
pivots: "laPivots", |
|||
valueColumnsEmptyMessage: "la drag cols to aggregate", |
|||
pivotColumnsEmptyMessage: "la drag here to pivot", |
|||
toolPanelButton: "la tool panel", |
|||
noRowsToShow: "数据为空", |
|||
pinColumn: "固定", |
|||
valueAggregation: "laValue Agg", |
|||
autosizeThiscolumn: "自动调整宽度", |
|||
autosizeAllColumns: "自动调整所有字段宽度", |
|||
groupBy: "分组", |
|||
ungroupBy: "不分组", |
|||
resetColumns: "重置列", |
|||
expandAll: "展开全部", |
|||
collapseAll: "关闭", |
|||
toolPanel: "⼯具⾯板", |
|||
export: "导出", |
|||
csvExport: "导出为CSV格式⽂件", |
|||
excelExport: "导出到Excel", |
|||
pinLeft: "左固定 <<", |
|||
pinRight: "右固定 >>", |
|||
noPin: "不要固定", |
|||
sum: "总数", |
|||
min: "最⼩值", |
|||
max: "最⼤值", |
|||
none: "⽆", |
|||
count: "总", |
|||
average: "平均值", |
|||
copy: "复制", |
|||
copyWithHeaders: "带表头复制", |
|||
copyWithGroupHeaders: '带分组表头复制', |
|||
ctrlC: "ctrl + C", |
|||
paste: "粘贴", |
|||
ctrlV: "ctrl + V" |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
export const localeText = { |
|||
page: "页", |
|||
more: "更多", |
|||
to: "到", |
|||
of: "of", |
|||
next: "下⼀页", |
|||
last: "上⼀页", |
|||
first: "⾸页", |
|||
previous: "上⼀页", |
|||
loadingOoo: "加载中...", |
|||
selectAll: "查询全部", |
|||
searchOoo: "查询...", |
|||
blanks: "空⽩", |
|||
filterOoo: "过滤...", |
|||
applyFilter: "保存过滤器...", |
|||
equals: "相等", |
|||
notEqual: "不相等", |
|||
lessThan: "⼩于", |
|||
greaterThan: "⼤于", |
|||
lessThanOrEqual: "⼩于等于", |
|||
greaterThanOrEqual: "⼤于等于", |
|||
inRange: "范围", |
|||
contains: "包含", |
|||
notContains: "不包含", |
|||
startsWith: "开始于", |
|||
endsWith: "结束于", |
|||
group: "组", |
|||
columns: "列", |
|||
filters: "筛选", |
|||
rowGroupColumns: "laPivot Cols", |
|||
rowGroupColumnsEmptyMessage: "la drag cols to group", |
|||
valueColumns: "laValue Cols", |
|||
pivotMode: "laPivot-Mode", |
|||
groups: "laGroups", |
|||
values: "值", |
|||
pivots: "laPivots", |
|||
valueColumnsEmptyMessage: "la drag cols to aggregate", |
|||
pivotColumnsEmptyMessage: "la drag here to pivot", |
|||
toolPanelButton: "la tool panel", |
|||
noRowsToShow: "数据为空", |
|||
pinColumn: "固定", |
|||
valueAggregation: "laValue Agg", |
|||
autosizeThiscolumn: "自动调整宽度", |
|||
autosizeAllColumns: "自动调整所有字段宽度", |
|||
groupBy: "分组", |
|||
ungroupBy: "不分组", |
|||
resetColumns: "重置列", |
|||
expandAll: "展开全部", |
|||
collapseAll: "关闭", |
|||
toolPanel: "⼯具⾯板", |
|||
export: "导出", |
|||
csvExport: "导出为CSV格式⽂件", |
|||
excelExport: "导出到Excel", |
|||
pinLeft: "左固定 <<", |
|||
pinRight: "右固定 >>", |
|||
noPin: "不要固定", |
|||
sum: "总数", |
|||
min: "最⼩值", |
|||
max: "最⼤值", |
|||
none: "⽆", |
|||
count: "总", |
|||
average: "平均值", |
|||
copy: "复制", |
|||
copyWithHeaders: "带表头复制", |
|||
copyWithGroupHeaders: '带分组表头复制', |
|||
ctrlC: "ctrl + C", |
|||
paste: "粘贴", |
|||
ctrlV: "ctrl + V" |
|||
} |
|||
@ -1,7 +0,0 @@ |
|||
export default interface IControls { |
|||
init(viewport: any): void |
|||
|
|||
dispose(): void |
|||
|
|||
animate?: () => void; |
|||
} |
|||
Loading…
Reference in new issue