<script setup lang="ts">
import { nextTick, ref, reactive, watch, computed } from 'vue';
import { edtorProps } from '../../model/propsData';
import ErrorIcon from '@/components/ErrorIcon/ErrorIcon.vue';
import ClearableIcon from '@/components/ClearableIcon/ClearableIcon.vue';
import { traduction } from '@/utils/language';
import { getStoreData } from '@/utils/composition';
const props: any = defineProps(edtorProps);
const emits = defineEmits([
'editor',
'cancel',
'confirm',
'clear',
'change',
'validate',
'focus',
'blur',
'input'
]);
defineExpose({
clearValidate() {
formRefObj.value.clearValidate('value');
},
validate() {
formRefObj.value.validateField('value');
},
getValidateResult() {
if (props?.rule?.validator) {
return props.rule.validator(props.rule, editData.value, () => {});
}
return true;
}
});
const language = computed(() => {
return getStoreData('loct', 'locale');
});
let trigger = 'blur';
const editorIconTip = traduction('COMMON_EDIT');
let editState = ref(false);
let suffixIconFlag = ref(false);
let validateResult = ref(true);
let focused: boolean = true;
const formRefObj = ref();
let editData = reactive({
value: props.value
});
let inputRule = reactive({
value: props.rule
});
const popoverVisible = ref(false);
watch(
() => props.value,
(val: string | number) => {
editData.value = val;
editState.value = false;
if (!focused && formRefObj && formRefObj.value) {
formRefObj.value.validateField('value');
}
}
);
watch(
() => props.rule,
(val: any) => {
inputRule.value = val;
setTrigger();
}
);
const saveState = computed(() => {
const { inputType } = props;
if (inputType === 'number' || !inputType) {
if (props.value || props.value === 0) {
return !validateResult.value || Number(props.value) === Number(editData.value);
} else {
return true;
}
}
return (
!validateResult.value ||
props.value?.toString() === editData.value?.toString() ||
editData.value === ''
);
});
function selfEditor() {
if (!props.disabled) {
emits('editor');
nextTick(() => {
editData.value = props.value;
editState.value = true;
});
}
}
function back() {
emits('cancel');
editState.value = false;
}
function save() {
if (saveState.value) {
return;
}
const { inputType } = props;
if (inputType === 'number' || !inputType) {
editData.value = Number(editData.value);
emits('confirm', editData.value);
}
emits('confirm', editData.value);
}
function setTrigger() {
if (props.rule && props.rule.trigger) {
trigger = props.rule.trigger;
}
}
setTrigger();
function clear() {
input('');
emits('clear');
if (!focused) {
formRefObj.value.validateField('value');
}
}
function change(value: string) {
emits('change', value);
}
function validate(key: string, state: boolean) {
validateResult.value = state;
emits('validate', state);
}
function focus() {
formRefObj.value.validateField('value');
focused = true;
emits('focus');
nextTick(() => {
mouseenter();
});
if (props.popoverSetting.show) {
popoverVisible.value = true;
}
}
function blur() {
emits('blur');
focused = false;
if (trigger === 'change') {
formRefObj.value.validateField('value');
}
nextTick(() => {
mouseleave();
});
if (props.popoverSetting.show) {
popoverVisible.value = false;
}
}
function input(value: string) {
emits('input', value);
nextTick(() => {
mouseenter();
});
}
function mouseenter() {
if (props.clearable) {
if (trigger === 'blue') {
if (validateResult.value && editData.value) {
suffixIconFlag.value = false;
} else {
suffixIconFlag.value = true;
}
} else {
if (editData.value) {
suffixIconFlag.value = false;
} else {
suffixIconFlag.value = true;
}
}
}
}
function mouseleave() {
if (props.clearable) {
if (focused && editData.value) {
suffixIconFlag.value = false;
} else {
suffixIconFlag.value = true;
}
}
}
</script>
<template>
<div :class="['editor-box', props.disabled ? 'disabled-btn' : '']">
<div v-if="!editState" class="btn-box" :class="`${language}-language`">
<span class="value">
<span :id="props.idStr + 'ShowNum'">{{ props.value }}</span>
{{ props.unit }}
</span>
<el-tooltip
:content="editorIconTip"
:teleported="props.teleported"
placement="top"
trigger-keys
>
<div
:id="props.idStr"
:class="['edit-icon', props.disabled ? 'disabled-btn' : '']"
@click="selfEditor"
>
<span class="icon-editor icon" />
</div>
</el-tooltip>
</div>
<div v-if="editState" class="edit-content">
<el-form
ref="formRefObj"
class="form"
:model="editData"
:rules="inputRule"
label-width="0px"
:validate-on-rule-change="false"
@validate="validate"
>
<el-form-item label="" prop="value" class="form-item">
<el-input
v-if="!props.popoverSetting.show"
v-model="editData.value"
v-addId.input="props.idStr + 'Input'"
v-clearable="props.clearable"
:clearable="props.clearable"
:input-style="props.inputStyle"
:class="props.classStr"
:type="props.inputType"
:placeholder="props.placeholder"
@mouseenter="mouseenter"
@mouseleave="mouseleave"
@clear="clear"
@input="input"
@change="change"
@focus="focus"
@blur="blur"
>
<template v-if="props.clearable" #suffix>
<ErrorIcon />
<ClearableIcon />
</template>
</el-input>
<el-popover
v-else
v-model:visible="popoverVisible"
:popper-class="props.popoverSetting.popperClass"
:width="props.popoverSetting.width"
:placement="props.popoverSetting.placement ? props.popoverSetting.placement : 'right'"
:trigger="props.popoverSetting.trigger ? props.popoverSetting.trigger : 'focus'"
trigger-keys
>
<span v-if="props.popoverSetting.type === 'ordinary' || !props.popoverSetting.type">
{{ props.popoverSetting.content }}
</span>
<component
:is="props.popoverSetting.popoverSlotSetting.component"
v-if="
props.popoverSetting.popoverSlotSetting && props.popoverSetting.type === 'complex'
"
:data="props.popoverSetting.popoverSlotSetting.data"
></component>
<template #reference>
<el-input
v-model="editData.value"
v-addId.input="props.idStr + 'Input'"
v-clearable="props.clearable"
:clearable="props.clearable"
:input-style="props.inputStyle"
:class="props.classStr"
:type="props.inputType"
:placeholder="props.placeholder"
@mouseenter="mouseenter"
@mouseleave="mouseleave"
@clear="clear"
@input="input"
@change="change"
@focus="focus"
@blur="blur"
>
<template v-if="props.clearable" #suffix>
<ErrorIcon />
<ClearableIcon />
</template>
</el-input>
</template>
</el-popover>
</el-form-item>
</el-form>
<div
:id="props.idStr + 'Save'"
class="btn btn-save"
:class="[saveState ? 'disabled' : '']"
@click="save"
>
{{ $t('COMMON_SAVE') }}
</div>
<div :id="props.idStr + 'Cancel'" class="btn" @click="back">
{{ $t('COMMON_CANCEL') }}
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.editor-box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
.btn-box {
display: flex;
align-items: center;
position: relative;
width: 60px;
line-height: 20px;
&.zh-language {
width: 85px;
}
&.en-language {
width: 140px;
}
.value {
color: var(--o-text-color-primary);
font-size: 16px;
font-weight: 500;
span {
white-space: nowrap;
width: auto;
}
}
.edit-icon {
margin-top: 3px;
margin-left: 5px;
cursor: pointer;
.icon-editor:before {
content: '\e906';
color: var(--o-text-color-tertiary);
}
.icon-editor:hover:before {
color: var(--o-color-primary-secondary);
}
}
}
.edit-content {
margin-left: 8px;
display: flex;
align-items: center;
.btn {
cursor: pointer;
color: var(--o-color-primary);
}
.btn-save {
margin: 0 8px;
}
.disabled {
cursor: not-allowed;
color: var(--o-text-color-tertiary);
}
:deep(.el-form) {
.el-form-item {
margin-bottom: 0px;
.el-input {
.el-input__inner {
line-height: 1px !important;
}
.el-input__inner::-webkit-input-placeholder {
font-size: 12px !important;
}
}
}
}
}
}
</style>