46 changed files with 595 additions and 76 deletions
@ -0,0 +1,323 @@ |
|||
<template> |
|||
<div v-show="showIfComputed"> |
|||
<q-field |
|||
ref="fieldRef" |
|||
v-model="codeMirrorValue" |
|||
:hide-bottom-space="true" |
|||
:hide-hint="true" |
|||
:outlined="true" |
|||
:dense="true" |
|||
v-bind="attrs" |
|||
:stack-label="stackLabelRef" |
|||
:rules="rulesComputed" |
|||
:readonly="readonlyIfComputed" |
|||
:disable="disableIfComputed" |
|||
style="position: relative" |
|||
@focus.stop.prevent="focus" |
|||
@blur.stop.prevent="blur" |
|||
@update:model-value="updateModelValue" |
|||
@change="changeValue" |
|||
> |
|||
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template> |
|||
<template #control> |
|||
<q-btn label="sdfds"></q-btn> |
|||
</template> |
|||
<template v-if="!Tools.isEmpty(codeMirrorValue) && attrs.button" #append> |
|||
<q-btn |
|||
round |
|||
dense |
|||
flat |
|||
v-bind="attrs.button" |
|||
:style="{ |
|||
content: '', |
|||
position: 'absolute', |
|||
bottom: '5px', |
|||
right: '5px', |
|||
}" |
|||
@click.stop.prevent="buttonClick(attrs.button)" |
|||
/> |
|||
</template> |
|||
</q-field> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { ref, useAttrs, onMounted, onUnmounted, watch, computed, toRaw } from 'vue'; |
|||
import { Tools } from '@/platform'; |
|||
import { FormValidators } from '@/platform/components'; |
|||
import { EditorView } from '@codemirror/view'; |
|||
import { EditorState, StateEffect, Compartment } from '@codemirror/state'; |
|||
import * as view from '@codemirror/view'; |
|||
import * as language from '@codemirror/language'; |
|||
import * as commands from '@codemirror/commands'; |
|||
import * as search from '@codemirror/search'; |
|||
import * as autocomplete from '@codemirror/autocomplete'; |
|||
|
|||
import { LanguageSupport } from '@codemirror/language'; |
|||
import { html } from '@codemirror/lang-html'; |
|||
import { java } from '@codemirror/lang-java'; |
|||
import { javascript } from '@codemirror/lang-javascript'; |
|||
import { json } from '@codemirror/lang-json'; |
|||
import { sql } from '@codemirror/lang-sql'; |
|||
import { xml } from '@codemirror/lang-xml'; |
|||
|
|||
const attrs = useAttrs(); |
|||
const rules = attrs.rules; |
|||
const fieldRef = ref(); |
|||
const props = defineProps({ |
|||
onChange: { |
|||
type: Function, |
|||
default: () => {}, |
|||
}, |
|||
modelValue: { type: String, default: '' }, |
|||
lang: { type: String, default: 'json' }, |
|||
width: { type: [Number, String], default: '100%' }, |
|||
height: { type: [Number, String], default: undefined }, |
|||
rows: { type: Number, default: 4 }, |
|||
tabSize: { type: Number, default: 4 }, |
|||
showIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return true; |
|||
}, |
|||
}, |
|||
required: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
requiredIf: { |
|||
type: Function, |
|||
default: undefined, |
|||
}, |
|||
readOnlyIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return false; |
|||
}, |
|||
}, |
|||
disableIf: { |
|||
type: Function, |
|||
default: () => { |
|||
return false; |
|||
}, |
|||
}, |
|||
form: { |
|||
type: Object, |
|||
default: undefined, |
|||
}, |
|||
}); |
|||
const emits = defineEmits(['update:modelValue', 'change']); |
|||
const codeMirrorValue = ref(props.modelValue); |
|||
watch( |
|||
() => props.modelValue, |
|||
(newVal, oldVal) => { |
|||
codeMirrorValue.value = newVal; |
|||
}, |
|||
); |
|||
|
|||
const rulesComputed = computed(() => { |
|||
let result = rules || <any>[]; |
|||
if (showIfComputed.value && requiredIfComputed.value) { |
|||
result.push(FormValidators.required()); |
|||
} else if (!showIfComputed.value) { |
|||
result = []; |
|||
} |
|||
if (fieldRef?.value) { |
|||
fieldRef.value.resetValidation(); |
|||
} |
|||
return result; |
|||
}); |
|||
|
|||
const showIfComputed = computed(() => { |
|||
return props.showIf({ |
|||
value: codeMirrorValue.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
const requiredIfComputed = computed(() => { |
|||
if (props.requiredIf) { |
|||
return ( |
|||
props.requiredIf({ |
|||
value: codeMirrorValue.value, |
|||
form: props.form, |
|||
}) || false |
|||
); |
|||
} else if (props.required) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}); |
|||
const readonlyIfComputed = computed(() => { |
|||
if (props.form && props.form.getStatus() === 'view') { |
|||
return true; |
|||
} |
|||
return props.readOnlyIf({ |
|||
value: codeMirrorValue.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
const disableIfComputed = computed(() => { |
|||
return props.disableIf({ |
|||
value: codeMirrorValue.value, |
|||
form: props.form, |
|||
}); |
|||
}); |
|||
|
|||
const basicSetup = [ |
|||
EditorState.allowMultipleSelections.of(true), |
|||
|
|||
//view.lineNumbers(), |
|||
//view.highlightActiveLine(), |
|||
view.highlightActiveLineGutter(), |
|||
view.highlightSpecialChars(), |
|||
view.drawSelection(), |
|||
view.dropCursor(), |
|||
view.rectangularSelection(), |
|||
view.crosshairCursor(), |
|||
|
|||
commands.history(), |
|||
|
|||
//language.foldGutter(), |
|||
language.indentOnInput(), |
|||
language.syntaxHighlighting(language.defaultHighlightStyle, { fallback: true }), |
|||
language.bracketMatching(), |
|||
|
|||
autocomplete.closeBrackets(), |
|||
autocomplete.autocompletion(), |
|||
|
|||
search.highlightSelectionMatches(), |
|||
|
|||
view.keymap.of([ |
|||
...commands.defaultKeymap, |
|||
...commands.historyKeymap, |
|||
...language.foldKeymap, |
|||
...autocomplete.completionKeymap, |
|||
...autocomplete.closeBracketsKeymap, |
|||
...search.searchKeymap, |
|||
//commands.indentWithTab, |
|||
]), |
|||
]; |
|||
|
|||
const getLanguage = (lang: string): LanguageSupport => { |
|||
lang = lang || 'json'; |
|||
switch (lang.toLowerCase()) { |
|||
case 'html': |
|||
return html(); |
|||
case 'java': |
|||
return java(); |
|||
case 'javascript': |
|||
return javascript(); |
|||
case 'json': |
|||
return json(); |
|||
case 'sql': |
|||
return sql(); |
|||
case 'xml': |
|||
return xml(); |
|||
default: |
|||
return json(); |
|||
} |
|||
}; |
|||
|
|||
const codemirrorRef = ref(); |
|||
// q-field 的 stack-label 属性是对 field 的 label 进行设置效果 |
|||
// 如果 field 有值时, 无论是否获得焦点 label 都缩小显示 |
|||
// 如果 field 无值时, 如果 field 获得焦点 label 就缩小显示, 否则 label 放大显示 |
|||
const stackLabelRef = ref(!Tools.isUndefinedOrNull(codeMirrorValue.value)); |
|||
|
|||
let editorView; |
|||
let isFocus = false; |
|||
|
|||
onMounted(() => { |
|||
if (codemirrorRef.value) { |
|||
let language = new Compartment(); |
|||
let tabSize = new Compartment(); |
|||
editorView = new EditorView({ |
|||
extensions: [ |
|||
basicSetup, |
|||
language.of(getLanguage(props.lang)), |
|||
tabSize.of(EditorState.tabSize.of(props.tabSize)), |
|||
EditorState.readOnly.of(props.readOnlyIf(props.form)), |
|||
EditorView.theme({ |
|||
'&': { |
|||
outline: 'none !important', |
|||
width: Tools.px(props.width), |
|||
height: props.height ? Tools.px(props.height) : props.rows * 22 + 'px', |
|||
}, |
|||
}), |
|||
// 以下代码可以添加内容变化后的操作, 为避免重复操作, 更新操作放到 blur 方法中了 |
|||
EditorView.updateListener.of(function (e) { |
|||
// emits('update:modelValue', e.state.doc.toString()); |
|||
updateModelValue(e.state.doc.toString()); |
|||
}), |
|||
], |
|||
parent: codemirrorRef.value, |
|||
doc: codeMirrorValue.value, |
|||
}); |
|||
watch( |
|||
() => codeMirrorValue.value, |
|||
() => { |
|||
// 当未获得焦点时,更新变更, 当获得焦点时不能更新 |
|||
if (!isFocus) { |
|||
editorView.dispatch({ changes: { from: 0, to: editorView.state.doc.length, insert: codeMirrorValue.value } }); |
|||
} |
|||
}, |
|||
); |
|||
} |
|||
}); |
|||
|
|||
onUnmounted(() => { |
|||
editorView.destroy(); |
|||
}); |
|||
|
|||
const focus = () => { |
|||
isFocus = true; |
|||
stackLabelRef.value = true; |
|||
}; |
|||
|
|||
const blur = () => { |
|||
isFocus = false; |
|||
const content = editorView.state.doc.toString(); |
|||
//emits('update:modelValue', content); |
|||
if (content) { |
|||
stackLabelRef.value = true; |
|||
} else { |
|||
stackLabelRef.value = false; |
|||
} |
|||
}; |
|||
|
|||
const getValue = () => { |
|||
return editorView.state.doc.toString(); |
|||
}; |
|||
|
|||
const setValue = (value: string) => { |
|||
editorView.dispatch({ changes: { from: 0, to: editorView.state.doc.length, insert: value } }); |
|||
}; |
|||
|
|||
const configure = (values) => { |
|||
editorView.dispatch({ effects: StateEffect.reconfigure.of(values) }); |
|||
}; |
|||
|
|||
const updateModelValue = (value) => { |
|||
emits('update:modelValue', value, props.form); |
|||
changeValue(value); |
|||
}; |
|||
const changeValue = (value) => { |
|||
emits('change', { |
|||
value: value, |
|||
form: props.form, |
|||
}); |
|||
}; |
|||
const buttonClick = (button) => { |
|||
if (button.click) { |
|||
button.click({ |
|||
value: codeMirrorValue.value, |
|||
form: props.form, |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
defineExpose({ |
|||
getValue, |
|||
setValue, |
|||
configure, |
|||
}); |
|||
</script> |
@ -0,0 +1,39 @@ |
|||
package io.sc.platform.core.autoconfigure; |
|||
|
|||
import io.sc.platform.core.Environment; |
|||
import io.sc.platform.core.service.support.MultiCorporationModeProperties; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
|||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.context.event.EventListener; |
|||
|
|||
import java.util.Set; |
|||
|
|||
/** |
|||
* 多法人模式自动配置类 |
|||
*/ |
|||
@Configuration |
|||
@EnableConfigurationProperties({MultiCorporationModeProperties.class}) |
|||
public class MultiCorporationModeAutoConfiguration { |
|||
/** |
|||
* 多法人模式配置属性类 |
|||
* 支持的持久化器包括: |
|||
* application.is-multi-corporation-mode = true |
|||
* application.is-multi-corporation-mode = false |
|||
*/ |
|||
@Autowired |
|||
private MultiCorporationModeProperties properties; |
|||
|
|||
@EventListener |
|||
public void environmentChangeEventHandle(EnvironmentChangeEvent event){ |
|||
Set<String> changedKeys =event.getKeys(); |
|||
for(String key : changedKeys) { |
|||
// 如果是多法人模式配置信息发生变化
|
|||
if (key.startsWith(Environment.KEY_IS_MULTI_CORPORATION_MODE)) { |
|||
Environment.getInstance().setMultiCorportationMode(properties.isMultiCorporationMode()); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
package io.sc.platform.core.service.support; |
|||
|
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
|
|||
/** |
|||
* 多法人模式配置属性类 |
|||
* 支持的持久化器包括: |
|||
* application.is-multi-corporation-mode = true |
|||
* application.is-multi-corporation-mode = false |
|||
*/ |
|||
@ConfigurationProperties("application") |
|||
public class MultiCorporationModeProperties { |
|||
private boolean isMultiCorporationMode; |
|||
|
|||
public boolean isMultiCorporationMode() { |
|||
return isMultiCorporationMode; |
|||
} |
|||
|
|||
public void setMultiCorporationMode(boolean multiCorporationMode) { |
|||
isMultiCorporationMode = multiCorporationMode; |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
package io.sc.platform.core.springboot; |
|||
|
|||
import io.sc.platform.core.Environment; |
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.env.EnvironmentPostProcessor; |
|||
import org.springframework.core.Ordered; |
|||
import org.springframework.core.env.ConfigurableEnvironment; |
|||
|
|||
/** |
|||
* Spring Boot 环境准备好后 |
|||
*/ |
|||
public class AfterEnvironmentProcessor implements EnvironmentPostProcessor, Ordered { |
|||
@Override |
|||
public int getOrder() { |
|||
return Ordered.HIGHEST_PRECEDENCE + 100; |
|||
} |
|||
|
|||
@Override |
|||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { |
|||
Environment.getInstance().setMultiCorportationMode(environment.getProperty(Environment.KEY_IS_MULTI_CORPORATION_MODE,Boolean.class,false)); |
|||
} |
|||
} |
Loading…
Reference in new issue