|
@ -1,84 +1,99 @@ |
|
|
<template> |
|
|
<template> |
|
|
<q-input v-model="valueRef" @update:model-value="valueChanged"> |
|
|
<div v-show="showIfComputed"> |
|
|
<template #prepend> |
|
|
<q-input |
|
|
<q-icon v-if="valueRef" :name="valueRef"> </q-icon> |
|
|
ref="iconRef" |
|
|
<w-icon-empty v-else></w-icon-empty> |
|
|
v-model="valueRef" |
|
|
</template> |
|
|
:hide-bottom-space="true" |
|
|
<template #append> |
|
|
:hide-hint="true" |
|
|
<q-btn icon="bi-search" size="10px" padding="2px" flat square unelevated :title="$t('select')"> |
|
|
:outlined="true" |
|
|
<q-popup-proxy v-model:model-value="isShow" anchor="bottom right" self="top right" :offset="[0, 10]" @show="show"> |
|
|
:dense="true" |
|
|
<q-splitter v-model="leftWidthRef" style="width: 800px; height: 300px; position: relative"> |
|
|
v-bind="attrs" |
|
|
<template #before> |
|
|
:rules="rulesComputed" |
|
|
<q-tabs v-model="selectedTab" align="left" vertical dense no-caps outside-arrows mobile-arrows> |
|
|
:readonly="readonlyIfComputed" |
|
|
<q-tab v-for="iconSet in iconSets" :key="iconSet.name" :name="iconSet.name"> |
|
|
:disable="disableIfComputed" |
|
|
<span class="w-[180px] text-left" :title="iconSet.label"> |
|
|
@update:model-value="valueChanged" |
|
|
{{ iconSet.label }} |
|
|
> |
|
|
</span> |
|
|
<template #prepend> |
|
|
</q-tab> |
|
|
<q-icon v-if="valueRef" :name="valueRef"> </q-icon> |
|
|
</q-tabs> |
|
|
<w-icon-empty v-else></w-icon-empty> |
|
|
</template> |
|
|
</template> |
|
|
<template #after> |
|
|
<template #append> |
|
|
<div class="pl-4 pt-2" style="width: 300px; height: 50px"> |
|
|
<q-btn icon="bi-search" size="10px" padding="2px" flat square unelevated :title="$t('select')"> |
|
|
<q-input v-model="searchRef" outlined dense> |
|
|
<q-popup-proxy v-model:model-value="isShow" anchor="bottom right" self="top right" :offset="[0, 10]" @show="show"> |
|
|
<template #append> |
|
|
<q-splitter v-model="leftWidthRef" style="width: 800px; height: 300px; position: relative"> |
|
|
<q-btn round flat icon="bi-search" size="10px" /> |
|
|
<template #before> |
|
|
</template> |
|
|
<q-tabs v-model="selectedTab" align="left" vertical dense no-caps outside-arrows mobile-arrows> |
|
|
</q-input> |
|
|
<q-tab v-for="iconSet in iconSets" :key="iconSet.name" :name="iconSet.name"> |
|
|
</div> |
|
|
<span class="w-[180px] text-left" :title="iconSet.label"> |
|
|
<q-tab-panels |
|
|
{{ iconSet.label }} |
|
|
v-model="selectedTab" |
|
|
</span> |
|
|
style="height: calc(100% - 50px)" |
|
|
</q-tab> |
|
|
animated |
|
|
</q-tabs> |
|
|
swipeable |
|
|
</template> |
|
|
vertical |
|
|
<template #after> |
|
|
transition-prev="jump-up" |
|
|
<div class="pl-4 pt-2" style="width: 300px; height: 50px"> |
|
|
transition-next="jump-up" |
|
|
<q-input v-model="searchRef" outlined dense> |
|
|
:keep-alive="true" |
|
|
<template #append> |
|
|
> |
|
|
<q-btn round flat icon="bi-search" size="10px" /> |
|
|
<q-tab-panel v-for="iconSet in iconSets" :key="iconSet.name" :name="iconSet.name" class="full-height"> |
|
|
</template> |
|
|
<div class="row full-height" style="overflow: scroll"> |
|
|
</q-input> |
|
|
<div v-for="item in iconSet.icons" :key="item"> |
|
|
</div> |
|
|
<div |
|
|
<q-tab-panels |
|
|
:id="item" |
|
|
v-model="selectedTab" |
|
|
class="grid justify-items-center q-pa-sm" |
|
|
style="height: calc(100% - 50px)" |
|
|
:title="item" |
|
|
animated |
|
|
:style=" |
|
|
swipeable |
|
|
item === valueRef |
|
|
vertical |
|
|
? 'background-color:var(--q-negative);' |
|
|
transition-prev="jump-up" |
|
|
: searchRef && item.indexOf(searchRef) !== -1 |
|
|
transition-next="jump-up" |
|
|
? 'background-color:var(--q-warning);' |
|
|
:keep-alive="true" |
|
|
: '' |
|
|
> |
|
|
" |
|
|
<q-tab-panel v-for="iconSet in iconSets" :key="iconSet.name" :name="iconSet.name" class="full-height"> |
|
|
> |
|
|
<div class="row full-height" style="overflow: scroll"> |
|
|
<q-icon size="26px" :name="item" class="cursor-pointer" @click="iconItemClick(item)"> </q-icon> |
|
|
<div v-for="item in iconSet.icons" :key="item"> |
|
|
|
|
|
<div |
|
|
|
|
|
:id="item" |
|
|
|
|
|
class="grid justify-items-center q-pa-sm" |
|
|
|
|
|
:title="item" |
|
|
|
|
|
:style=" |
|
|
|
|
|
item === valueRef |
|
|
|
|
|
? 'background-color:var(--q-negative);' |
|
|
|
|
|
: searchRef && item.indexOf(searchRef) !== -1 |
|
|
|
|
|
? 'background-color:var(--q-warning);' |
|
|
|
|
|
: '' |
|
|
|
|
|
" |
|
|
|
|
|
> |
|
|
|
|
|
<q-icon size="26px" :name="item" class="cursor-pointer" @click="iconItemClick(item)"> </q-icon> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</q-tab-panel> |
|
|
</q-tab-panel> |
|
|
</q-tab-panels> |
|
|
</q-tab-panels> |
|
|
</template> |
|
|
</template> |
|
|
</q-splitter> |
|
|
</q-splitter> |
|
|
</q-popup-proxy> |
|
|
</q-popup-proxy> |
|
|
</q-btn> |
|
|
</q-btn> |
|
|
<!-- 恢复默认值按钮 --> |
|
|
<!-- 恢复默认值按钮 --> |
|
|
<q-btn |
|
|
<q-btn |
|
|
v-if="restore" |
|
|
v-if="restore" |
|
|
icon="bi-arrow-counterclockwise" |
|
|
icon="bi-arrow-counterclockwise" |
|
|
size="10px" |
|
|
size="10px" |
|
|
padding="2px" |
|
|
padding="2px" |
|
|
flat |
|
|
flat |
|
|
square |
|
|
square |
|
|
unelevated |
|
|
unelevated |
|
|
:title="$t('restore')" |
|
|
:title="$t('restore')" |
|
|
:style="{ 'margin-left': '5px', border: '1px solid #e5e7eb', color: restoreValue, 'background-color': computedStoreBackgroundColorValue }" |
|
|
:style="{ 'margin-left': '5px', border: '1px solid #e5e7eb', color: restoreValue, 'background-color': computedStoreBackgroundColorValue }" |
|
|
@click="restoreDefaultValue" |
|
|
@click="restoreDefaultValue" |
|
|
></q-btn> |
|
|
></q-btn> |
|
|
</template> |
|
|
</template> |
|
|
</q-input> |
|
|
</q-input> |
|
|
</div> |
|
|
</template> |
|
|
</template> |
|
|
<script setup lang="ts"> |
|
|
<script setup lang="ts"> |
|
|
import { ref, toRaw, onMounted } from 'vue'; |
|
|
import { ref, toRaw, onMounted, computed, useAttrs, watch } from 'vue'; |
|
|
import { Tools } from '@/platform'; |
|
|
import { Tools } from '@/platform'; |
|
|
|
|
|
import { FormValidators } from '@/platform/components'; |
|
|
import bootstrap from './icons/bootstrap.json'; |
|
|
import bootstrap from './icons/bootstrap.json'; |
|
|
import materialIcons from './icons/material-icons.json'; |
|
|
import materialIcons from './icons/material-icons.json'; |
|
|
import materialSymbolsOutlined from './icons/material-symbols-outlined.json'; |
|
|
import materialSymbolsOutlined from './icons/material-symbols-outlined.json'; |
|
@ -87,9 +102,42 @@ import fontawesomeBrands from './icons/fontawesome-v6-icons-brands.json'; |
|
|
import fontawesomeRegular from './icons/fontawesome-v6-icons-regular.json'; |
|
|
import fontawesomeRegular from './icons/fontawesome-v6-icons-regular.json'; |
|
|
import fontawesomeSolid from './icons/fontawesome-v6-icons-solid.json'; |
|
|
import fontawesomeSolid from './icons/fontawesome-v6-icons-solid.json'; |
|
|
|
|
|
|
|
|
|
|
|
const attrs = useAttrs(); |
|
|
|
|
|
const rules = attrs.rules; |
|
|
|
|
|
const iconRef = ref(); |
|
|
const props = defineProps({ |
|
|
const props = defineProps({ |
|
|
modelValue: { type: String, default: '' }, |
|
|
modelValue: { type: String, default: '' }, |
|
|
restore: { type: Boolean, default: false }, |
|
|
restore: { type: Boolean, default: false }, |
|
|
|
|
|
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 emit = defineEmits(['update:modelValue']); |
|
|
const emit = defineEmits(['update:modelValue']); |
|
|
|
|
|
|
|
@ -108,8 +156,45 @@ const selectedTab = ref('bootstrap'); |
|
|
const isShow = ref(false); |
|
|
const isShow = ref(false); |
|
|
const searchRef = ref(''); |
|
|
const searchRef = ref(''); |
|
|
const valueRef = ref(props.modelValue || 'bi-arrow-up-left-square'); |
|
|
const valueRef = ref(props.modelValue || 'bi-arrow-up-left-square'); |
|
|
|
|
|
watch( |
|
|
|
|
|
() => props.modelValue, |
|
|
|
|
|
(newVal, oldVal) => { |
|
|
|
|
|
valueRef.value = newVal; |
|
|
|
|
|
}, |
|
|
|
|
|
); |
|
|
const restoreValue = toRaw(props.modelValue || ''); |
|
|
const restoreValue = toRaw(props.modelValue || ''); |
|
|
|
|
|
|
|
|
|
|
|
const rulesComputed = computed(() => { |
|
|
|
|
|
let result = rules || <any>[]; |
|
|
|
|
|
if (showIfComputed.value && requiredIfComputed.value) { |
|
|
|
|
|
result.push(FormValidators.required()); |
|
|
|
|
|
} else if (!showIfComputed.value) { |
|
|
|
|
|
result = []; |
|
|
|
|
|
} |
|
|
|
|
|
if (iconRef?.value) { |
|
|
|
|
|
iconRef.value.resetValidation(); |
|
|
|
|
|
} |
|
|
|
|
|
return result; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const showIfComputed = computed(() => { |
|
|
|
|
|
return props.showIf(props.form); |
|
|
|
|
|
}); |
|
|
|
|
|
const requiredIfComputed = computed(() => { |
|
|
|
|
|
if (props.requiredIf) { |
|
|
|
|
|
return props.requiredIf(props.form) || false; |
|
|
|
|
|
} else if (props.required) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
return false; |
|
|
|
|
|
}); |
|
|
|
|
|
const readonlyIfComputed = computed(() => { |
|
|
|
|
|
return props.readonlyIf(props.form); |
|
|
|
|
|
}); |
|
|
|
|
|
const disableIfComputed = computed(() => { |
|
|
|
|
|
return props.disableIf(props.form); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
if (Tools.isEmpty(valueRef.value)) { |
|
|
if (Tools.isEmpty(valueRef.value)) { |
|
|
selectedTab.value = 'bootstrap'; |
|
|
selectedTab.value = 'bootstrap'; |
|
|
} else if (valueRef.value.startsWith('bi')) { |
|
|
} else if (valueRef.value.startsWith('bi')) { |
|
|