fix: 修复部分缺陷
This commit is contained in:
parent
ba36f0966b
commit
67d30ed976
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bunny-auth-admin",
|
||||
"version": "3.0.0",
|
||||
"version": "4.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
|
|
@ -21,9 +21,7 @@ const i18nStore = userI18nStore();
|
|||
const i18n = useI18n();
|
||||
const { $storage } = useNav();
|
||||
|
||||
/**
|
||||
* * 设置多语言内容
|
||||
*/
|
||||
/* 设置多语言内容 */
|
||||
const setI18n = async () => {
|
||||
await i18nStore.loadI18nMap();
|
||||
const languageData = JSON.parse(localStorage.getItem('i18nStore') as any);
|
||||
|
@ -44,9 +42,7 @@ const setI18n = async () => {
|
|||
i18n.mergeLocaleMessage(locale, languageData.i18n[locale]);
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当前语言类别
|
||||
*/
|
||||
/* 当前语言类别 */
|
||||
const currentLocale = computed(() => {
|
||||
const languageData = JSON.parse(localStorage.getItem('i18nStore') as any);
|
||||
const local = languageData ? languageData.i18n.local : {};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { computed, defineComponent, onMounted, reactive, unref, watch } from 'vue';
|
||||
import { watch, unref, computed, reactive, onMounted, defineComponent } from 'vue';
|
||||
import { countToProps } from './props';
|
||||
import { isNumber } from '@pureadmin/utils';
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import './rebound.css';
|
||||
import { defineComponent, onBeforeMount, onBeforeUnmount, ref, unref } from 'vue';
|
||||
import { ref, unref, onBeforeMount, defineComponent, onBeforeUnmount } from 'vue';
|
||||
import { reboundProps } from './props';
|
||||
|
||||
export default defineComponent({
|
|
@ -1,12 +1,12 @@
|
|||
.scroll-num {
|
||||
animation: enhance-bounce-in-down 1s calc(var(--delay) * 1s) forwards;
|
||||
width: var(--width, 20px);
|
||||
height: var(--height, calc(var(--width, 20px) * 1.8));
|
||||
color: var(--color, #333);
|
||||
font-size: var(--height, calc(var(--width, 20px) * 1.1));
|
||||
height: var(--height, calc(var(--width, 20px) * 1.8));
|
||||
line-height: var(--height, calc(var(--width, 20px) * 1.8));
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
width: var(--width, 20px);
|
||||
overflow: hidden;
|
||||
animation: enhance-bounce-in-down 1s calc(var(--delay) * 1s) forwards;
|
||||
}
|
||||
|
||||
ul {
|
|
@ -2,26 +2,26 @@ import './circled.css';
|
|||
import Cropper from 'cropperjs';
|
||||
import { ElUpload } from 'element-plus';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { computed, defineComponent, onMounted, onUnmounted, type PropType, ref, unref } from 'vue';
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
import { longpress } from '@/directives/longpress';
|
||||
import { directive as tippy, useTippy } from 'vue-tippy';
|
||||
import { debounce, delay, downloadByBase64, isArray, useResizeObserver } from '@pureadmin/utils';
|
||||
import { useTippy, directive as tippy } from 'vue-tippy';
|
||||
import { type PropType, ref, unref, computed, onMounted, onUnmounted, defineComponent } from 'vue';
|
||||
import { delay, debounce, isArray, downloadByBase64, useResizeObserver } from '@pureadmin/utils';
|
||||
import {
|
||||
ArrowDown,
|
||||
ArrowH,
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
ArrowUp,
|
||||
ArrowV,
|
||||
ChangeIcon,
|
||||
DownloadIcon,
|
||||
Reload,
|
||||
Upload,
|
||||
ArrowH,
|
||||
ArrowV,
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
ArrowLeft,
|
||||
ChangeIcon,
|
||||
ArrowRight,
|
||||
RotateLeft,
|
||||
SearchPlus,
|
||||
RotateRight,
|
||||
SearchMinus,
|
||||
SearchPlus,
|
||||
Upload,
|
||||
DownloadIcon,
|
||||
} from './svg';
|
||||
|
||||
type Options = Cropper.Options;
|
||||
|
@ -101,7 +101,7 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return ['p-[6px]', 'h-[30px]', 'w-[30px]', 'outline-none', 'rounded-[4px]', 'cursor-pointer', 'hover:bg-[rgba(0,0,0,0.06)]'];
|
||||
return ['p-[6px]', 'h-[30px]', 'w-[30px]', 'outline-hidden', 'rounded-[4px]', 'cursor-pointer', 'hover:bg-[rgba(0,0,0,0.06)]'];
|
||||
});
|
||||
|
||||
const getWrapperStyle = computed((): CSSProperties => {
|
||||
|
@ -124,7 +124,7 @@ export default defineComponent({
|
|||
async function init() {
|
||||
const imgEl = unref(imgElRef);
|
||||
if (!imgEl) return;
|
||||
const result: any = new Cropper(imgEl, {
|
||||
cropper.value = new Cropper(imgEl, {
|
||||
...defaultOptions,
|
||||
ready: () => {
|
||||
isReady.value = true;
|
||||
|
@ -142,11 +142,6 @@ export default defineComponent({
|
|||
},
|
||||
...props.options,
|
||||
});
|
||||
|
||||
// 如果图片不存在直接将加载变为加载完成
|
||||
if (!result.ready) emit('readied', cropper.value);
|
||||
|
||||
cropper.value = result;
|
||||
}
|
||||
|
||||
function realTimeCroppered() {
|
||||
|
@ -226,30 +221,55 @@ export default defineComponent({
|
|||
return () => (
|
||||
<div class="flex flex-wrap w-[60px] justify-between">
|
||||
<ElUpload accept="image/*" show-file-list={false} before-upload={beforeUpload}>
|
||||
<Upload class={iconClass.value} v-tippy={{ content: '上传', placement: 'left-start' }} />
|
||||
<Upload
|
||||
class={iconClass.value}
|
||||
v-tippy={{
|
||||
content: '上传',
|
||||
placement: 'left-start',
|
||||
}}
|
||||
/>
|
||||
</ElUpload>
|
||||
<DownloadIcon
|
||||
class={iconClass.value}
|
||||
v-tippy={{ content: '下载', placement: 'right-start' }}
|
||||
v-tippy={{
|
||||
content: '下载',
|
||||
placement: 'right-start',
|
||||
}}
|
||||
onClick={() => downloadByBase64(imgBase64.value, 'cropping.png')}
|
||||
/>
|
||||
<ChangeIcon
|
||||
class={iconClass.value}
|
||||
v-tippy={{ content: '圆形、矩形裁剪', placement: 'left-start' }}
|
||||
v-tippy={{
|
||||
content: '圆形、矩形裁剪',
|
||||
placement: 'left-start',
|
||||
}}
|
||||
onClick={() => {
|
||||
inCircled.value = !inCircled.value;
|
||||
realTimeCroppered();
|
||||
}}
|
||||
/>
|
||||
<Reload class={iconClass.value} v-tippy={{ content: '重置', placement: 'right-start' }} onClick={() => handCropper('reset')} />
|
||||
<Reload
|
||||
class={iconClass.value}
|
||||
v-tippy={{
|
||||
content: '重置',
|
||||
placement: 'right-start',
|
||||
}}
|
||||
onClick={() => handCropper('reset')}
|
||||
/>
|
||||
<ArrowUp
|
||||
class={iconClass.value}
|
||||
v-tippy={{ content: '上移(可长按)', placement: 'left-start' }}
|
||||
v-tippy={{
|
||||
content: '上移(可长按)',
|
||||
placement: 'left-start',
|
||||
}}
|
||||
v-longpress={[() => handCropper('move', [0, -10]), '0:100']}
|
||||
/>
|
||||
<ArrowDown
|
||||
class={iconClass.value}
|
||||
v-tippy={{ content: '下移(可长按)', placement: 'right-start' }}
|
||||
v-tippy={{
|
||||
content: '下移(可长按)',
|
||||
placement: 'right-start',
|
||||
}}
|
||||
v-longpress={[() => handCropper('move', [0, 10]), '0:100']}
|
||||
/>
|
||||
<ArrowLeft
|
||||
|
@ -262,21 +282,58 @@ export default defineComponent({
|
|||
/>
|
||||
<ArrowRight
|
||||
class={iconClass.value}
|
||||
v-tippy={{ content: '右移(可长按)', placement: 'right-start' }}
|
||||
v-tippy={{
|
||||
content: '右移(可长按)',
|
||||
placement: 'right-start',
|
||||
}}
|
||||
v-longpress={[() => handCropper('move', [10, 0]), '0:100']}
|
||||
/>
|
||||
<ArrowH class={iconClass.value} v-tippy={{ content: '水平翻转', placement: 'left-start' }} onClick={() => handCropper('scaleX', -1)} />
|
||||
<ArrowV class={iconClass.value} v-tippy={{ content: '垂直翻转', placement: 'right-start' }} onClick={() => handCropper('scaleY', -1)} />
|
||||
<RotateLeft class={iconClass.value} v-tippy={{ content: '逆时针旋转', placement: 'left-start' }} onClick={() => handCropper('rotate', -45)} />
|
||||
<RotateRight class={iconClass.value} v-tippy={{ content: '顺时针旋转', placement: 'right-start' }} onClick={() => handCropper('rotate', 45)} />
|
||||
<ArrowH
|
||||
class={iconClass.value}
|
||||
v-tippy={{
|
||||
content: '水平翻转',
|
||||
placement: 'left-start',
|
||||
}}
|
||||
onClick={() => handCropper('scaleX', -1)}
|
||||
/>
|
||||
<ArrowV
|
||||
class={iconClass.value}
|
||||
v-tippy={{
|
||||
content: '垂直翻转',
|
||||
placement: 'right-start',
|
||||
}}
|
||||
onClick={() => handCropper('scaleY', -1)}
|
||||
/>
|
||||
<RotateLeft
|
||||
class={iconClass.value}
|
||||
v-tippy={{
|
||||
content: '逆时针旋转',
|
||||
placement: 'left-start',
|
||||
}}
|
||||
onClick={() => handCropper('rotate', -45)}
|
||||
/>
|
||||
<RotateRight
|
||||
class={iconClass.value}
|
||||
v-tippy={{
|
||||
content: '顺时针旋转',
|
||||
placement: 'right-start',
|
||||
}}
|
||||
onClick={() => handCropper('rotate', 45)}
|
||||
/>
|
||||
<SearchPlus
|
||||
class={iconClass.value}
|
||||
v-tippy={{ content: '放大(可长按)', placement: 'left-start' }}
|
||||
v-tippy={{
|
||||
content: '放大(可长按)',
|
||||
placement: 'left-start',
|
||||
}}
|
||||
v-longpress={[() => handCropper('zoom', 0.1), '0:100']}
|
||||
/>
|
||||
<SearchMinus
|
||||
class={iconClass.value}
|
||||
v-tippy={{ content: '缩小(可长按)', placement: 'right-start' }}
|
||||
v-tippy={{
|
||||
content: '缩小(可长按)',
|
||||
placement: 'right-start',
|
||||
}}
|
||||
v-longpress={[() => handCropper('zoom', -0.1), '0:100']}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<script lang="tsx" setup>
|
||||
<script setup lang="tsx">
|
||||
import { ref } from 'vue';
|
||||
import ReCropper from '@/components/ReCropper';
|
||||
import { formatBytes } from '@pureadmin/utils';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
|
||||
defineOptions({
|
||||
name: 'ReCropperPreview',
|
||||
});
|
||||
|
||||
defineProps({
|
||||
imgSrc: String,
|
||||
|
@ -31,30 +34,20 @@ defineExpose({ hidePopover });
|
|||
|
||||
<template>
|
||||
<div v-loading="!showPopover" element-loading-background="transparent">
|
||||
<el-popover ref="popoverRef" :visible="showPopover" placement="right" popper-style="top:260px" width="18vw">
|
||||
<el-popover ref="popoverRef" :visible="showPopover" placement="right" width="18vw">
|
||||
<template #reference>
|
||||
<div class="w-[18vw]">
|
||||
<ReCropper ref="refCropper" :src="imgSrc" circled @cropper="onCropper" @readied="showPopover = true" />
|
||||
<p v-show="showPopover" class="mt-1 text-center">{{ $t('cropper_preview_tips') }}</p>
|
||||
<p v-show="showPopover" class="mt-1 text-center">温馨提示:右键上方裁剪区可开启功能菜单</p>
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex flex-wrap justify-center items-center text-center">
|
||||
<el-image v-if="cropperImg" :preview-src-list="Array.of(cropperImg)" :src="cropperImg" class="cropper-img-preview" fit="contain" />
|
||||
<el-image v-if="cropperImg" :src="cropperImg" :preview-src-list="Array.of(cropperImg)" fit="cover" />
|
||||
<div v-if="infos" class="mt-1">
|
||||
<p>{{ $t('image_size') }}:{{ parseInt(infos.width) }} × {{ parseInt(infos.height) }}{{ $t('pixel') }}</p>
|
||||
<p>{{ $t('file_size') }}:{{ formatBytes(infos.size) }}({{ infos.size }} {{ $t('bytes') }}</p>
|
||||
<p>图像大小:{{ parseInt(infos.width) }} × {{ parseInt(infos.height) }}像素</p>
|
||||
<p>文件大小:{{ formatBytes(infos.size) }}({{ infos.size }} 字节)</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cropper-img-preview {
|
||||
height: 200px;
|
||||
|
||||
:deep(.el-image__inner) {
|
||||
max-height: 310px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -16,7 +16,7 @@ defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="list.length">
|
||||
<div v-if="list.length" class="mb-4">
|
||||
<NoticeItem v-for="(item, index) in list" :key="index" :noticeItem="item" />
|
||||
</div>
|
||||
<el-empty v-else :description="emptyText" />
|
||||
|
|
|
@ -10,21 +10,22 @@ import { useTranslationLang } from '../../hooks/useTranslationLang';
|
|||
import { usePermissionStoreHook } from '@/store/permission';
|
||||
import LaySidebarItem from '../lay-sidebar/components/SidebarItem.vue';
|
||||
import LaySidebarFullScreen from '../lay-sidebar/components/SidebarFullScreen.vue';
|
||||
|
||||
import GlobalizationIcon from '@/assets/svg/globalization.svg?component';
|
||||
import LogoutCircleRLine from '@iconify-icons/ri/logout-circle-r-line';
|
||||
import Setting from '@iconify-icons/ri/settings-3-line';
|
||||
import Check from '@iconify-icons/ep/check';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { userI18nTypeStore } from '@/store/i18n/i18nType';
|
||||
import GlobalizationIcon from '@/assets/svg/globalization.svg?component';
|
||||
|
||||
const menuRef = ref();
|
||||
const showLogo = ref(storageLocal().getItem<StorageConfigs>(`${responsiveStorageNameSpace()}configure`)?.showLogo ?? true);
|
||||
|
||||
const { t, route, locale, translationCh, translationEn } = useTranslationLang(menuRef);
|
||||
const { t, route, locale, translation } = useTranslationLang(menuRef);
|
||||
const { title, logout, onPanel, getLogo, username, userAvatar, backTopMenu, avatarsStyle, getDropdownItemStyle, getDropdownItemClass } = useNav();
|
||||
|
||||
const defaultActive = computed(() => (!isAllEmpty(route.meta?.activePath) ? route.meta.activePath : route.path));
|
||||
|
||||
const i18nTypeStore = userI18nTypeStore();
|
||||
nextTick(() => {
|
||||
menuRef.value?.handleResize();
|
||||
});
|
||||
|
@ -49,29 +50,21 @@ onMounted(() => {
|
|||
<!-- 菜单搜索 -->
|
||||
<LaySearch id="header-search" />
|
||||
<!-- 国际化 -->
|
||||
<el-dropdown id="header-translation" trigger="click">
|
||||
<GlobalizationIcon class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none" />
|
||||
<el-dropdown trigger="click">
|
||||
<GlobalizationIcon class="hover:text-primary hover:!bg-[transparent] w-[20px] h-[20px] ml-1.5 cursor-pointer outline-none duration-300" />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="translation">
|
||||
<el-dropdown-item
|
||||
:class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
|
||||
:style="getDropdownItemStyle(locale, 'zh')"
|
||||
@click="translationCh"
|
||||
v-for="item in i18nTypeStore.translationTypeList"
|
||||
:key="item.key"
|
||||
:class="['dark:!text-white', getDropdownItemClass(locale, item.key)]"
|
||||
:style="getDropdownItemStyle(locale, item.key)"
|
||||
@click="translation(item.key)"
|
||||
>
|
||||
<span v-show="locale === 'zh'" class="check-zh">
|
||||
<span v-show="locale === item.key" class="check">
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</span>
|
||||
简体中文
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
:class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
|
||||
:style="getDropdownItemStyle(locale, 'en')"
|
||||
@click="translationEn"
|
||||
>
|
||||
<span v-show="locale === 'en'" class="check-en">
|
||||
<IconifyIconOffline :icon="Check" />
|
||||
</span>
|
||||
English
|
||||
{{ item.value }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts" setup>
|
||||
import ReCropperPreview from '@/components/CropperPreview';
|
||||
import ReCropperPreview from '@/components/ReCropperPreview';
|
||||
import { sexConstant } from '@/enums/baseConstant';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { useAdminUserStore } from '@/store/system/adminUser';
|
||||
|
|
|
@ -8,7 +8,7 @@ import { $t } from '@/plugins/i18n';
|
|||
import { isAddUserinfo } from '@/views/system/admin-user/utils/columns';
|
||||
import ResetPasswordDialog from '@/components/Table/ResetPasswords.vue';
|
||||
import { deviceDetection, handleTree } from '@pureadmin/utils';
|
||||
import CropperPreview from '@/components/CropperPreview';
|
||||
import CropperPreview from '@/components/ReCropperPreview';
|
||||
import AssignUserToRole from '@/views/system/admin-user/components/assign-roles-to-user.vue';
|
||||
import { useUserStore } from '@/store/system/user';
|
||||
import { useDeptStore } from '@/store/system/dept';
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { onMounted, ref } from 'vue';
|
||||
import ReCol from '@/components/ReCol';
|
||||
import { chartData, useDark } from './utils';
|
||||
import { ReNormalCountTo } from '@/components/CountTo';
|
||||
import { ReNormalCountTo } from '@/components/ReCountTo';
|
||||
import ChartLine from '@/views/welcome/components/ChartLine.vue';
|
||||
import ChartRound from '@/views/welcome/components/ChartRound.vue';
|
||||
import { getServerCommitList, getWebCommitList, serverCommitList, webCommitList } from '@/views/welcome/utils';
|
||||
|
|
Loading…
Reference in New Issue