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