Merge branch 'main' of github.com:pure-admin/vue-pure-admin into gitee

This commit is contained in:
xiaoxian521 2023-10-17 11:39:36 +08:00
commit 227a7b7a2a
13 changed files with 2751 additions and 722 deletions

View File

@ -12,6 +12,7 @@
"Grey": false,
"Weak": false,
"HideTabs": false,
"HideFooter": false,
"SidebarStatus": true,
"EpThemeColor": "#409EFF",
"ShowLogo": true,

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,15 @@
import iconifyIconOffline from "./src/iconifyIconOffline";
import iconifyIconOnline from "./src/iconifyIconOnline";
import iconSelect from "./src/Select.vue";
import fontIcon from "./src/iconfont";
/** 本地图标组件 */
const IconifyIconOffline = iconifyIconOffline;
/** 在线图标组件 */
const IconifyIconOnline = iconifyIconOnline;
/** iconfont组件 */
/** `IconSelect`图标选择器组件 */
const IconSelect = iconSelect;
/** `iconfont`组件 */
const FontIcon = fontIcon;
export { IconifyIconOffline, IconifyIconOnline, FontIcon };
export { IconifyIconOffline, IconifyIconOnline, IconSelect, FontIcon };

View File

@ -1,7 +1,9 @@
<script setup lang="ts">
import { cloneDeep } from "@pureadmin/utils";
import { IconJson } from "@/components/ReIcon/data";
import { cloneDeep, isAllEmpty } from "@pureadmin/utils";
import { ref, computed, CSSProperties, toRef, watch } from "vue";
import Search from "@iconify-icons/ri/search-eye-line";
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined;
defineOptions({
@ -16,15 +18,15 @@ const props = defineProps({
});
const emit = defineEmits<{ (e: "update:modelValue", v: string) }>();
const visible = ref(false);
const inputValue = toRef(props, "modelValue");
const iconList = ref(IconJson);
const icon = ref("add-location");
const icon = ref();
const currentActiveType = ref("ep:");
//
const copyIconList = cloneDeep(iconList.value);
const pageSize = ref(96);
const totalPage = ref(0);
// 35
const pageSize = ref(35);
const currentPage = ref(1);
//
@ -36,8 +38,8 @@ const tabsList = [
name: "ep:"
},
{
label: "Font Awesome 4",
name: "fa:"
label: "Remix Icon",
name: "ri:"
},
{
label: "Font Awesome 5 Solid",
@ -45,20 +47,14 @@ const tabsList = [
}
];
const pageList = computed(() => {
if (currentPage.value === 1) {
return copyIconList[currentActiveType.value]
.filter(v => v.includes(filterValue.value))
.slice(currentPage.value - 1, pageSize.value);
} else {
return copyIconList[currentActiveType.value]
.filter(v => v.includes(filterValue.value))
.slice(
pageSize.value * (currentPage.value - 1),
pageSize.value * (currentPage.value - 1) + pageSize.value
);
}
});
const pageList = computed(() =>
copyIconList[currentActiveType.value]
.filter(i => i.includes(filterValue.value))
.slice(
(currentPage.value - 1) * pageSize.value,
currentPage.value * pageSize.value
)
);
const iconItemStyle = computed((): ParameterCSSProperties => {
return item => {
@ -71,50 +67,63 @@ const iconItemStyle = computed((): ParameterCSSProperties => {
};
});
function setVal() {
currentActiveType.value = props.modelValue.substring(
0,
props.modelValue.indexOf(":") + 1
);
icon.value = props.modelValue.substring(props.modelValue.indexOf(":") + 1);
}
function onBeforeEnter() {
if (isAllEmpty(icon.value)) return;
setVal();
//
const curIconIndex = copyIconList[currentActiveType.value].findIndex(
i => i === icon.value
);
currentPage.value = Math.ceil((curIconIndex + 1) / pageSize.value);
}
function onAfterLeave() {
filterValue.value = "";
}
function handleClick({ props }) {
currentPage.value = 1;
currentActiveType.value = props.name;
emit(
"update:modelValue",
currentActiveType.value + iconList.value[currentActiveType.value][0]
);
icon.value = iconList.value[currentActiveType.value][0];
}
function onChangeIcon(item) {
icon.value = item;
emit("update:modelValue", currentActiveType.value + item);
visible.value = false;
}
function onCurrentChange(page) {
currentPage.value = page;
}
function onClear() {
icon.value = "";
emit("update:modelValue", "");
}
watch(
() => {
return props.modelValue;
},
() => {
if (props.modelValue) {
currentActiveType.value = props.modelValue.substring(
0,
props.modelValue.indexOf(":") + 1
);
icon.value = props.modelValue.substring(
props.modelValue.indexOf(":") + 1
);
}
},
() => pageList.value,
() =>
(totalPage.value = copyIconList[currentActiveType.value].filter(i =>
i.includes(filterValue.value)
).length),
{ immediate: true }
);
watch(
() => {
return filterValue.value;
},
() => {
currentPage.value = 1;
}
() => props.modelValue,
val => val && setVal(),
{ immediate: true }
);
watch(
() => filterValue.value,
() => (currentPage.value = 1)
);
</script>
@ -129,14 +138,15 @@ watch(
:popper-options="{
placement: 'auto'
}"
:visible="visible"
@before-enter="onBeforeEnter"
@after-leave="onAfterLeave"
>
<template #reference>
<div
class="w-[40px] h-[32px] cursor-pointer flex justify-center items-center"
@click="visible = !visible"
>
<IconifyIconOnline :icon="currentActiveType + icon" />
<IconifyIconOffline v-if="!icon" :icon="Search" />
<IconifyIconOnline v-else :icon="inputValue" />
</div>
</template>
@ -160,7 +170,7 @@ watch(
v-for="(item, key) in pageList"
:key="key"
:title="item"
class="icon-item p-2 cursor-pointer mr-2 mt-1 flex justify-center items-center border border-solid"
class="icon-item p-2 cursor-pointer mr-2 mt-1 flex justify-center items-center border border-[#e5e7eb]"
:style="iconItemStyle(item)"
@click="onChangeIcon(item)"
>
@ -175,16 +185,31 @@ watch(
</el-tab-pane>
</el-tabs>
<el-pagination
small
:total="copyIconList[currentActiveType].length"
:page-size="pageSize"
:current-page="currentPage"
background
layout="prev, pager, next"
class="flex items-center justify-center h-10"
@current-change="onCurrentChange"
/>
<div
class="w-full h-9 flex items-center overflow-auto border-t border-[#e5e7eb]"
>
<el-pagination
class="flex-auto ml-2"
:total="totalPage"
:current-page="currentPage"
:page-size="pageSize"
:pager-count="5"
layout="pager"
background
small
@current-change="onCurrentChange"
/>
<el-button
class="justify-end mr-2 ml-2"
type="danger"
size="small"
text
bg
@click="onClear"
>
清空
</el-button>
</div>
</el-popover>
</template>
</el-input>
@ -231,6 +256,14 @@ watch(
box-shadow: 0 2px 5px rgb(0 0 0 / 6%);
}
:deep(.el-tabs__nav-wrap::after) {
height: 0;
}
:deep(.el-tabs__nav-wrap) {
padding: 0 24px;
}
:deep(.el-tabs__content) {
margin-top: 4px;
}

View File

@ -1,7 +1,7 @@
import { h, defineComponent } from "vue";
import { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline";
// Iconify Icon在Vue里本地使用用于内网环境https://docs.iconify.design/icon-components/vue/offline.html
// Iconify Icon在Vue里本地使用用于内网环境
export default defineComponent({
name: "IconifyIconOffline",
components: { IconifyIcon },

View File

@ -1,4 +1,5 @@
<script setup lang="ts">
import Footer from "./footer/index.vue";
import { useGlobal } from "@pureadmin/utils";
import backTop from "@/assets/svg/back_top.svg?component";
import { h, computed, Transition, defineComponent } from "vue";
@ -24,6 +25,10 @@ const hideTabs = computed(() => {
return $storage?.configure.hideTabs;
});
const hideFooter = computed(() => {
return $storage?.configure.hideFooter;
});
const layout = computed(() => {
return $storage?.layout.layout === "vertical";
});
@ -32,9 +37,15 @@ const getSectionStyle = computed(() => {
return [
hideTabs.value && layout ? "padding-top: 48px;" : "",
!hideTabs.value && layout ? "padding-top: 85px;" : "",
hideTabs.value && !layout.value ? "padding-top: 48px" : "",
hideTabs.value && !layout.value ? "padding-top: 48px;" : "",
!hideTabs.value && !layout.value ? "padding-top: 85px;" : "",
props.fixedHeader ? "" : "padding-top: 0;"
props.fixedHeader
? ""
: `padding-top: 0;${
hideTabs.value
? "min-height: calc(100vh - 48px);"
: "min-height: calc(100vh - 86px);"
}`
];
});
@ -78,30 +89,44 @@ const transitionMain = defineComponent({
>
<router-view>
<template #default="{ Component, route }">
<el-scrollbar v-if="props.fixedHeader">
<el-scrollbar
v-if="props.fixedHeader"
:wrap-style="{
display: 'flex'
}"
:view-style="{
display: 'flex',
flex: 'auto',
overflow: 'auto',
'flex-direction': 'column'
}"
>
<el-backtop title="回到顶部" target=".app-main .el-scrollbar__wrap">
<backTop />
</el-backtop>
<transitionMain :route="route">
<keep-alive
v-if="isKeepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<div class="grow">
<transitionMain :route="route">
<keep-alive
v-if="isKeepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component
:is="Component"
:key="route.fullPath"
class="main-content"
/>
</keep-alive>
<component
v-else
:is="Component"
:key="route.fullPath"
class="main-content"
/>
</keep-alive>
<component
v-else
:is="Component"
:key="route.fullPath"
class="main-content"
/>
</transitionMain>
</transitionMain>
</div>
<Footer v-if="!hideFooter" />
</el-scrollbar>
<div v-else>
<div v-else class="grow">
<transitionMain :route="route">
<keep-alive
v-if="isKeepAlive"
@ -123,6 +148,9 @@ const transitionMain = defineComponent({
</div>
</template>
</router-view>
<!-- 页脚 -->
<Footer v-if="!hideFooter && !props.fixedHeader" />
</section>
</template>
@ -136,8 +164,9 @@ const transitionMain = defineComponent({
.app-main-nofixed-header {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
min-height: 100vh;
}
.main-content {

View File

@ -0,0 +1,29 @@
<script lang="ts" setup>
import { getConfig } from "@/config";
const TITLE = getConfig("Title");
</script>
<template>
<footer class="layout-footer">
MIT © 2020-PRESENT
<a
class="ml-1 hover:text-primary"
href="https://github.com/pure-admin"
target="_blank"
>
{{ TITLE }}
</a>
</footer>
</template>
<style lang="scss" scoped>
.layout-footer {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 0 0 8px;
color: #c0c4cc;
}
</style>

View File

@ -66,6 +66,7 @@ const settings = reactive({
tabsVal: $storage.configure.hideTabs,
showLogo: $storage.configure.showLogo,
showModel: $storage.configure.showModel,
hideFooter: $storage.configure.hideFooter,
multiTagsCache: $storage.configure.multiTagsCache
});
@ -111,12 +112,20 @@ const weekChange = (value): void => {
storageConfigureChange("weak", value);
};
/** 隐藏标签页设置 */
const tagsChange = () => {
const showVal = settings.tabsVal;
storageConfigureChange("hideTabs", showVal);
emitter.emit("tagViewsChange", showVal as unknown as string);
};
/** 隐藏页脚设置 */
const hideFooterChange = () => {
const hideFooter = settings.hideFooter;
storageConfigureChange("hideFooter", hideFooter);
};
/** 标签页持久化设置 */
const multiTagsCacheChange = () => {
const multiTagsCache = settings.multiTagsCache;
storageConfigureChange("multiTagsCache", multiTagsCache);
@ -218,6 +227,7 @@ onBeforeMount(() => {
settings.weakVal &&
document.querySelector("html")?.setAttribute("class", "html-weakness");
settings.tabsVal && tagsChange();
settings.hideFooter && hideFooterChange();
});
});
</script>
@ -344,6 +354,17 @@ onBeforeMount(() => {
@change="tagsChange"
/>
</li>
<li>
<span class="dark:text-white">隐藏页脚</span>
<el-switch
v-model="settings.hideFooter"
inline-prompt
inactive-color="#a6a6a6"
active-text="开"
inactive-text="关"
@change="hideFooterChange"
/>
</li>
<li>
<span class="dark:text-white">侧边栏Logo</span>
<el-switch

View File

@ -36,6 +36,7 @@ export function useLayout() {
grey: $config?.Grey ?? false,
weak: $config?.Weak ?? false,
hideTabs: $config?.HideTabs ?? false,
hideFooter: $config.HideFooter ?? false,
showLogo: $config?.ShowLogo ?? true,
showModel: $config?.ShowModel ?? "smart",
multiTagsCache: $config?.MultiTagsCache ?? false

View File

@ -24,6 +24,7 @@ export const injectResponsiveStorage = (app: App, config: PlatformConfigs) => {
grey: config.Grey ?? false,
weak: config.Weak ?? false,
hideTabs: config.HideTabs ?? false,
hideFooter: config.HideFooter ?? false,
showLogo: config.ShowLogo ?? true,
showModel: config.ShowModel ?? "smart",
multiTagsCache: config.MultiTagsCache ?? false

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref } from "vue";
import IconSelect from "@/components/ReIcon/src/Select.vue";
import { IconSelect } from "@/components/ReIcon";
defineOptions({
name: "IconSelect"

View File

@ -22,9 +22,9 @@ onMounted(() => {
videoAttributes: {
crossOrigin: "anonymous"
},
url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
url: "//lf3-static.bytednsdoc.com/obj/eden-cn/nupenuvpxnuvo/xgplayer_doc/xgplayer-demo.mp4",
poster:
"https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg",
"//lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg",
fluid: deviceDetection(),
//
playbackRate: [0.5, 0.75, 1, 1.5, 2]

3
types/global.d.ts vendored
View File

@ -89,6 +89,7 @@ declare global {
Grey?: boolean;
Weak?: boolean;
HideTabs?: boolean;
HideFooter?: boolean;
SidebarStatus?: boolean;
EpThemeColor?: string;
ShowLogo?: boolean;
@ -125,6 +126,7 @@ declare global {
grey?: boolean;
weak?: boolean;
hideTabs?: boolean;
hideFooter?: boolean;
sidebarStatus?: boolean;
epThemeColor?: string;
showLogo?: boolean;
@ -158,6 +160,7 @@ declare global {
grey?: boolean;
weak?: boolean;
hideTabs?: boolean;
hideFooter?: boolean;
showLogo?: boolean;
showModel?: string;
multiTagsCache?: boolean;