<script lang="ts" setup>
|
import type { ScrollActionType } from '@jnpf/ui';
|
|
import { onMounted, reactive, ref, toRefs, watch } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { ScrollContainer, ymCustomJson, ymIconJson } from '@jnpf/ui';
|
import { BasicForm, useForm } from '@jnpf/ui/form';
|
|
import { useClipboard } from '@vueuse/core';
|
import { cloneDeep } from 'lodash-es';
|
|
defineOptions({ name: 'SysDataIcons' });
|
|
const ymIcon = ymIconJson.glyphs.map((o) => `icon-ym icon-ym-${o.font_class}`);
|
const ymCustom = ymCustomJson.glyphs.map((o) => `ym-custom ym-custom-${o.font_class}`);
|
|
const { createMessage } = useMessage();
|
const [registerForm, { resetFields }] = useForm({
|
baseColProps: { span: 6 },
|
showActionButtonGroup: true,
|
showAdvancedButton: true,
|
compact: true,
|
schemas: [
|
{
|
field: 'keyword',
|
label: '关键词',
|
component: 'Input',
|
componentProps: {
|
placeholder: '请输入关键词',
|
submitOnPressEnter: true,
|
},
|
},
|
],
|
});
|
const state = reactive({
|
activeKey: '1',
|
currentPage: 1,
|
keyword: '',
|
pageSize: 100,
|
loading: false,
|
finish: false,
|
ymIcon,
|
ymCustom,
|
cacheList: [],
|
iconList: [],
|
});
|
const { activeKey, iconList } = toRefs(state);
|
const infiniteBody = ref<Nullable<ScrollActionType>>(null);
|
|
watch(
|
() => state.activeKey,
|
() => {
|
resetFields();
|
},
|
);
|
|
function handleSubmit(values) {
|
state.keyword = values?.keyword || '';
|
handleSearch();
|
}
|
function handleReset() {
|
state.keyword = '';
|
handleSearch();
|
}
|
function handleSearch() {
|
infiniteBody.value?.scrollTo(0, 0);
|
state.currentPage = 1;
|
state.finish = false;
|
const key: string = state.activeKey === '1' ? 'ymIcon' : 'ymCustom';
|
state.iconList = [];
|
state.cacheList = state.keyword ? state[key].filter((o) => o.includes(state.keyword)) : cloneDeep(state[key]);
|
getList();
|
}
|
function getList() {
|
state.loading = true;
|
setTimeout(() => {
|
const res = state.cacheList.slice((state.currentPage - 1) * state.pageSize, state.currentPage * state.pageSize);
|
if (res.length < state.pageSize) state.finish = true;
|
state.iconList = [...state.iconList, ...res];
|
state.loading = false;
|
}, 0);
|
}
|
function bindScroll() {
|
const bodyRef = infiniteBody.value;
|
const vBody = bodyRef?.getScrollWrap();
|
vBody?.addEventListener('scroll', () => {
|
if (vBody.scrollHeight - vBody.clientHeight - vBody.scrollTop <= 200 && !state.loading && !state.finish) {
|
state.currentPage += 1;
|
getList();
|
}
|
});
|
}
|
function handleCopy(item) {
|
const { copy } = useClipboard({ legacy: true });
|
copy(item);
|
createMessage.success('复制成功');
|
}
|
onMounted(() => {
|
handleReset();
|
bindScroll();
|
});
|
</script>
|
<template>
|
<div class="jnpf-content-wrapper icons-wrapper">
|
<div class="jnpf-content-wrapper-center">
|
<div class="jnpf-content-wrapper-search-box">
|
<BasicForm class="search-form" @register="registerForm" @submit="handleSubmit" @reset="handleReset" />
|
</div>
|
<div class="jnpf-content-wrapper-content flex flex-col bg-white">
|
<a-tabs v-model:active-key="activeKey" class="jnpf-content-wrapper-tabs">
|
<a-tab-pane key="1" tab="ymIcon图标" />
|
<a-tab-pane key="2" tab="更多图标" />
|
</a-tabs>
|
<div class="flex-1 overflow-hidden">
|
<ScrollContainer ref="infiniteBody">
|
<a-row>
|
<a-col :span="6" v-for="item in iconList" :key="item" @click="handleCopy(item)" :title="item" class="icon-item">
|
<i :class="item"></i>
|
<span>{{ item }}</span>
|
</a-col>
|
</a-row>
|
<jnpf-empty v-if="iconList.length === 0" />
|
</ScrollContainer>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
<style lang="scss" scoped>
|
.icons-wrapper {
|
.icon-item {
|
height: 40px;
|
padding: 0 10px;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
line-height: 38px;
|
color: #6b7a99;
|
white-space: nowrap;
|
cursor: pointer;
|
border: 1px dashed transparent;
|
|
i {
|
margin-right: 14px;
|
font-size: 16px;
|
line-height: 40px;
|
vertical-align: top;
|
}
|
|
span {
|
line-height: 40px;
|
vertical-align: top;
|
}
|
|
&:hover {
|
border-color: var(--primary-color);
|
|
i {
|
font-size: 30px;
|
}
|
}
|
}
|
}
|
</style>
|