处理弹窗的放大缩小

This commit is contained in:
MTrun 2021-12-20 13:36:54 +08:00
parent f37ed1f3d3
commit 8dc4769b64
19 changed files with 345 additions and 106 deletions
package.jsonpnpm-lock.yaml
src
components/AppleControlBtn
i18n
plugins
settings
store/modules
designStore
langStore
styles/common
utils
views/project
items/components
layout/components/Sider
types

@ -12,15 +12,16 @@
"mockjs": "^1.1.0",
"naive-ui": "^2.19.9",
"pinia": "^2.0.6",
"screenfull": "^6.0.0",
"vue": "^3.2.16",
"vue-i18n": "^9.2.0-beta.23",
"vue-router": "4.0.12"
},
"devDependencies": {
"@vicons/ionicons5": "~0.11.0",
"@types/node": "^16.11.1",
"@typescript-eslint/eslint-plugin": "^5.6.0",
"@typescript-eslint/parser": "^5.6.0",
"@vicons/ionicons5": "~0.11.0",
"@vitejs/plugin-vue": "^1.9.3",
"@vitejs/plugin-vue-jsx": "^1.2.0",
"@vue/compiler-sfc": "^3.2.20",
@ -31,7 +32,7 @@
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.2.0",
"lodash": "^4.17.21",
"lodash": "~4.17.21",
"prettier": "^2.5.1",
"sass": "^1.43.2",
"sass-loader": "^12.2.0",

15
pnpm-lock.yaml generated

@ -16,13 +16,14 @@ specifiers:
eslint-plugin-import: ^2.25.3
eslint-plugin-prettier: ^4.0.0
eslint-plugin-vue: ^8.2.0
lodash: ^4.17.21
lodash: ~4.17.21
mockjs: ^1.1.0
naive-ui: ^2.19.9
pinia: ^2.0.6
prettier: ^2.5.1
sass: ^1.43.2
sass-loader: ^12.2.0
screenfull: ^6.0.0
typescript: ^4.4.4
vite: ^2.6.10
vite-plugin-importer: ^0.2.5
@ -34,11 +35,11 @@ specifiers:
vue-tsc: ^0.28.7
dependencies:
'@vicons/ionicons5': rg.cnpmjs.org/@vicons/ionicons5/0.11.0
axios: rg.cnpmjs.org/axios/0.23.0
mockjs: rg.cnpmjs.org/mockjs/1.1.0
naive-ui: rg.cnpmjs.org/naive-ui/2.21.5_vue@3.2.24
pinia: rg.cnpmjs.org/pinia/2.0.6_typescript@4.5.2+vue@3.2.24
screenfull: rg.cnpmjs.org/screenfull/6.0.0
vue: rg.cnpmjs.org/vue/3.2.24
vue-i18n: rg.cnpmjs.org/vue-i18n/9.2.0-beta.23_vue@3.2.24
vue-router: rg.cnpmjs.org/vue-router/4.0.12_vue@3.2.24
@ -47,6 +48,7 @@ devDependencies:
'@types/node': rg.cnpmjs.org/@types/node/16.11.12
'@typescript-eslint/eslint-plugin': rg.cnpmjs.org/@typescript-eslint/eslint-plugin/5.6.0_16d83f5c41c3abb1061a82b07c18e4f3
'@typescript-eslint/parser': rg.cnpmjs.org/@typescript-eslint/parser/5.6.0_eslint@8.4.1+typescript@4.5.2
'@vicons/ionicons5': rg.cnpmjs.org/@vicons/ionicons5/0.11.0
'@vitejs/plugin-vue': rg.cnpmjs.org/@vitejs/plugin-vue/1.10.2_vite@2.7.1
'@vitejs/plugin-vue-jsx': rg.cnpmjs.org/@vitejs/plugin-vue-jsx/1.3.1
'@vue/compiler-sfc': rg.cnpmjs.org/@vue/compiler-sfc/3.2.24
@ -877,7 +879,7 @@ packages:
resolution: {integrity: sha1-VBhb+lcqCd9wCU2xlU8ov78TY+0=, registry: http://r.cnpmjs.org/, tarball: https://rg.cnpmjs.org/@vicons/ionicons5/download/@vicons/ionicons5-0.11.0.tgz}
name: '@vicons/ionicons5'
version: 0.11.0
dev: false
dev: true
rg.cnpmjs.org/@vitejs/plugin-vue-jsx/1.3.1:
resolution: {integrity: sha512-Ku0pnlG0CuFfkvwOe3TEHS7noqBIBR61JbdvH6F6i3IqJv8+0+tcyusR+EoFwi7YrA2vdP26oorWyGv3wDt5kg==, registry: http://r.cnpmjs.org/, tarball: https://rg.cnpmjs.org/@vitejs/plugin-vue-jsx/download/@vitejs/plugin-vue-jsx-1.3.1.tgz}
@ -3729,6 +3731,13 @@ packages:
immutable: rg.cnpmjs.org/immutable/4.0.0
dev: true
rg.cnpmjs.org/screenfull/6.0.0:
resolution: {integrity: sha1-b383v+GcXuUJMaxDjB/jgNW1/0Q=, registry: http://r.cnpmjs.org/, tarball: https://rg.cnpmjs.org/screenfull/download/screenfull-6.0.0.tgz}
name: screenfull
version: 6.0.0
engines: {node: ^14.13.1 || >=16.0.0}
dev: false
rg.cnpmjs.org/seemly/0.3.3:
resolution: {integrity: sha512-mAyqemz41e9HiZPMXAn7NtTExJgztwco5cdZjrt/iViU/oFeav+Q8K1c93M/tIZZ00QkT65JMr4xXQk7Vv5hWQ==, registry: http://r.cnpmjs.org/, tarball: https://rg.cnpmjs.org/seemly/download/seemly-0.3.3.tgz}
name: seemly

@ -1,6 +1,6 @@
<template>
<div class="go-apple-control-btn">
<template v-for="item in btnList" :key="item.key">
<template v-for="item in filterBtnList" :key="item.key">
<div
class="btn"
:class="[item.key, disabled && 'disabled']"
@ -14,13 +14,28 @@
</div>
</template>
<script lang="ts" setup>
import { renderIcon } from '@/utils/index'
import { icon } from '@/plugins'
import { computed } from 'vue'
import { screenfullFn } from '@/utils'
const emit = defineEmits(['close', 'remove', 'resize'])
const emit = defineEmits(['close', 'remove', 'resize', 'fullResize'])
const props = defineProps({
//
disabled: {
request: false,
type: Boolean,
default: false
},
//
hidden: {
request: false,
type: Array,
default: []
},
// 使
narrow: {
request: false,
type: Boolean,
default: false
}
@ -28,6 +43,16 @@ const props = defineProps({
const { CloseIcon, RemoveIcon, ResizeIcon } = icon.ionicons5
const filterBtnList = computed(() => {
const res = btnList.filter(e => {
return props.hidden.findIndex(p => e.key == p) === -1
})
return res
})
const isFull = computed(() => {
return props.narrow && screenfullFn(true)
})
const btnList = [
{
title: '关闭',
@ -40,14 +65,16 @@ const btnList = [
icon: RemoveIcon
},
{
title: '放大',
key: 'resize',
title: isFull ? '缩小' : '放大',
key: props.narrow ? 'fullResize' : 'resize',
icon: ResizeIcon
}
]
const handleClick = (key: 'close' | 'remove' | 'resize') => {
console.log(key)
const handleClick = (key: 'close' | 'remove' | 'resize' | 'fullResize') => {
if (key === 'fullResize') screenfullFn()
//
if (key === 'remove') screenfullFn(true) && screenfullFn()
emit(key)
}
</script>
@ -74,7 +101,7 @@ const handleClick = (key: 'close' | 'remove' | 'resize') => {
font-weight: bold;
border-radius: 50%;
&.disabled {
pointer-events:none;
pointer-events: none;
}
.icon-base {
opacity: 0;
@ -89,7 +116,8 @@ const handleClick = (key: 'close' | 'remove' | 'resize') => {
.remove {
background-color: $--color-warn;
}
.resize {
.resize,
.fullResize {
background-color: $--color-success;
}
}

@ -1,7 +1,7 @@
//语言
import { lang } from '@/settings/designSetting'
import { createI18n } from 'vue-i18n' //引入vue-i18n组件
import { getLocalStorage } from '@/utils/index'
import { getLocalStorage } from '@/utils/storage'
import { GO_LANG_SELECT } from '@/settings/storageConst'
import zh from './zh/index'
import en from './en/index'

@ -6,10 +6,11 @@ import {
CopyOutline as CopyIcon,
Trash as TrashIcon,
Pencil as PencilIcon,
Hammer as HammerIcon,
HammerOutline as HammerIcon,
ApertureSharp as ApertureSharpIcon,
DownloadOutline as DownloadIcon,
Open as OpenIcon
Open as OpenIcon,
Send as SendIcon
} from '@vicons/ionicons5'
// ionicons5 在这里
@ -35,7 +36,9 @@ const ionicons5 = {
// 下载
DownloadIcon,
// 导出
OpenIcon
OpenIcon,
// 导出
SendIcon,
}
// https://www.xicons.org/#/ 还有很多

@ -41,7 +41,7 @@ export const theme = {
// 默认是否开启深色主题
darkTheme: true,
//系统主题色
appTheme: '#63e2b7',
appTheme: '#51d6a9',
//系统内置主题色列表
appThemeList
}
@ -53,7 +53,7 @@ export const asideWidth = '270'
export const asideCollapsedWidth = '60'
// 修改边框圆角
export const borderRadius = '4px'
export const borderRadius = '6px'
// 轮播间隔
export const carouselInterval = 4000

@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
import { store } from '@/store'
import { theme } from '@/settings/designSetting'
import { DesignStateType } from './designStore.d'
import { setLocalStorage, getLocalStorage } from '@/utils/index'
import { setLocalStorage, getLocalStorage } from '@/utils/storage'
import { GO_Theme_SELECT } from '@/settings/storageConst'
import { ThemeEnum } from '@/enums/styleEnum'

@ -3,7 +3,7 @@ import { lang } from '@/settings/designSetting'
import { LangStateType } from './langStore.d'
import { LangEnum } from '@/enums/styleEnum'
import i18n from '@/i18n/index'
import { setLocalStorage } from '@/utils/index'
import { setLocalStorage } from '@/utils/storage'
import { GO_LANG_SELECT } from '@/settings/storageConst'
export const useLangStore = defineStore({

@ -3,11 +3,13 @@
$light: (
// 文字颜色
color: $--color-text,
// aside 背景
aside-background_color: $--color-light-fill-1,
//背景
background_color: $--color-light-fill-3,
//渐变背景
background-image:
linear-gradient(120deg, $--color-text-1 0%, $--color-text-1 100%),
linear-gradient(120deg, $--color-light-fill 0%, $--color-light-fill 100%),
// 斑点背景
background-point:
(

@ -12,7 +12,7 @@ $--color-text-4: #f2f3f5;
// 白色
$--color-light-fill: #fff;
$--color-light-fill-1: #f7f8fa;
$--color-light-fill-1: #fafafc;
$--color-light-fill-2: #f2f3f5;
$--color-light-fill-3: #e5e6eb;
$--color-light-fill-4: #c9cdd4;

@ -1,6 +1,6 @@
import { h } from 'vue'
import { NIcon } from 'naive-ui'
import screenfull from 'screenfull'
/**
* * ID
* @param { Number } randomLength
@ -64,56 +64,17 @@ export const requireUrl = (path: string, name: string) => {
return new URL(`${path}/${name}`, import.meta.url).href
}
/**
* *
* @param k
* @param v
* @returns RemovableRef
*/
export const setLocalStorage = <T>(k: string, v: T) => {
try {
window.localStorage.setItem(k, JSON.stringify(v))
} catch (error) {
return false
}
}
export const screenfullFn = (isFullscreen?: boolean, isEnabled?: boolean) => {
// 是否是全屏
if (isFullscreen) return screenfull.isFullscreen
/**
* *
* @returns any
*/
export const getLocalStorage: (k: string) => any = (k: string) => {
const item = window.localStorage.getItem(k)
try {
return item ? JSON.parse(item) : item
} catch (err) {
return item
}
}
// 是否支持全屏
if (isEnabled) return screenfull.isEnabled
/**
* *
* @param k
* @param v
* @returns RemovableRef
*/
export const setSessionStorage = <T>(k: string, v: T) => {
try {
window.sessionStorage.setItem(k, JSON.stringify(v))
} catch (error) {
return false
}
}
/**
* *
* @returns any
*/
export const getSessionStorage: (k: string) => any = (k: string) => {
const item = window.sessionStorage.getItem(k)
try {
return item ? JSON.parse(item) : item
} catch (err) {
return item
if (screenfull.isEnabled) {
screenfull.toggle()
return
}
// TODO lang
window['$message'].warning('您的浏览器不支持全屏功能!')
}

54
src/utils/storage.ts Normal file

@ -0,0 +1,54 @@
/**
* *
* @param k
* @param v
* @returns RemovableRef
*/
export const setLocalStorage = <T>(k: string, v: T) => {
try {
window.localStorage.setItem(k, JSON.stringify(v))
} catch (error) {
return false
}
}
/**
* *
* @returns any
*/
export const getLocalStorage: (k: string) => any = (k: string) => {
const item = window.localStorage.getItem(k)
try {
return item ? JSON.parse(item) : item
} catch (err) {
return item
}
}
/**
* *
* @param k
* @param v
* @returns RemovableRef
*/
export const setSessionStorage = <T>(k: string, v: T) => {
try {
window.sessionStorage.setItem(k, JSON.stringify(v))
} catch (error) {
return false
}
}
/**
* *
* @returns any
*/
export const getSessionStorage: (k: string) => any = (k: string) => {
const item = window.sessionStorage.getItem(k)
try {
return item ? JSON.parse(item) : item
} catch (err) {
return item
}
}

@ -4,37 +4,41 @@
<div class="list-content">
<!-- 顶部按钮 -->
<n-space class="list-content-top">
<AppleControlBtn @close="deleteHanlde" />
<AppleControlBtn @close="deleteHanlde" @resize="resizeHandle" />
</n-space>
<!-- 中间 -->
<div class="list-content-img">
<n-image
object-fit="contain"
height="200"
preview-disabled
:src="requireUrl('.', '20211219181327.png')"
:alt="CardData.title"
:alt="cardData.title"
/>
</div>
</div>
<template #action>
<Skeleton v-if="loading" :loading="loading" text round size="small" />
<n-space v-else justify="space-between">
<n-space class="list-footer" justify="space-between">
<n-text>
{{ CardData.title || '' }}
{{ cardData.title || '' }}
</n-text>
<!-- 工具 -->
<n-space>
<n-text>
<n-badge class="animation-twinkle" dot :color="CardData.release ? '#34c749' : '#fcbc40'" />
{{ CardData.release ? '已发布' : '未发布' }}
<n-badge
class="animation-twinkle"
dot
:color="cardData.release ? '#34c749' : '#fcbc40'"
/>
{{ cardData.release ? '已发布' : '未发布' }}
</n-text>
<template v-for="item in fnBtnList" :key="item.key">
<template v-if="item.key === 'select'">
<n-dropdown
trigger="hover"
placement="bottom-start"
placement="bottom"
:options="selectOptions"
:show-arrow="true"
@select="handleSelect"
@ -47,11 +51,16 @@
</n-dropdown>
</template>
<n-button v-else size="small">
<template #icon>
<component :is="item.icon" />
<n-tooltip v-else placement="bottom" trigger="hover">
<template #trigger>
<n-button size="small">
<template #icon>
<component :is="item.icon" />
</template>
</n-button>
</template>
</n-button>
<span> {{ item.label }}</span>
</n-tooltip>
</template>
</n-space>
<!-- end -->
@ -73,17 +82,26 @@ const {
TrashIcon,
PencilIcon,
ApertureSharpIcon,
DownloadIcon
DownloadIcon,
HammerIcon,
SendIcon
} = icon.ionicons5
const loading = ref<boolean>(true)
const dialog = useDialog()
const message = useMessage()
defineProps({
CardData: Object
const emit = defineEmits(['resize'])
const props = defineProps({
cardData: Object
})
const fnBtnList = [
{
label: '编辑',
key: 'edit',
icon: renderIcon(HammerIcon)
},
{
lable: '更多',
key: 'select',
@ -107,6 +125,15 @@ const selectOptions = [
key: 'rename',
icon: renderIcon(PencilIcon)
},
{
type: 'divider',
key: 'd1'
},
{
label: props.cardData?.release ? '取消发布' : '发布',
key: 'send',
icon: renderIcon(SendIcon)
},
{
label: '下载',
key: 'download',
@ -114,7 +141,7 @@ const selectOptions = [
},
{
type: 'divider',
key: 'd1'
key: 'd2'
},
{
label: '删除',
@ -131,6 +158,7 @@ const requireUrl = (path: string, name: string) => {
return new URL(`${path}/${name}`, import.meta.url).href
}
//
const deleteHanlde = () => {
goDialog(dialog.warning, {
type: 'delete',
@ -140,9 +168,10 @@ const deleteHanlde = () => {
})
}
setTimeout(() => {
loading.value = false
}, 1500)
//
const resizeHandle = () => {
emit('resize', props.cardData)
}
</script>
<style lang="scss" scoped>
@ -157,7 +186,7 @@ $contentHeight: 200px;
@extend .go-point-bg;
&-top {
position: absolute;
top: 5px;
top: 10px;
left: 10px;
height: 22px;
}
@ -172,5 +201,8 @@ $contentHeight: 200px;
}
}
}
.list-footer {
line-height: 30px;
}
}
</style>

@ -7,24 +7,21 @@
responsive="screen"
>
<n-grid-item v-for="item in list" :key="item.id">
<Card :CardData="item" />
<Card :cardData="item" @resize="resizeHandle" />
</n-grid-item>
</n-grid>
</div>
<ModalCard :show="modalShow" :cardData="modalData" @close="closeModal" />
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { Card } from '../Card/index'
import { ModalCard } from '../ModalCard/index'
import {
EllipsisHorizontalSharp as EllipsisHorizontalCircleSharpIcon,
CopyOutline as CopyIcon
} from '@vicons/ionicons5'
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 500)
const list = reactive([
{
@ -34,21 +31,40 @@ const list = reactive([
},
{
id: 2,
title: '物料1'
title: '物料2',
release: false
},
{
id: 3,
title: '物料1'
title: '物料3',
release: false
},
{
id: 4,
title: '物料1'
title: '物料4',
release: false
},
{
id: 5,
title: '物料1'
title: '物料5',
release: false
}
])
const modalData = ref({})
const modalShow = ref(false)
// modal
const closeModal = () => {
modalShow.value = false
}
// modal
const resizeHandle = (cardData: object) => {
modalShow.value = true
modalData.value = cardData
}
</script>
<style lang="scss" scoped>

Binary file not shown.

After

(image error) Size: 1.3 MiB

@ -0,0 +1,3 @@
import ModalCard from './index.vue'
export { ModalCard }

@ -0,0 +1,127 @@
<template>
<n-modal class="go-modal-card" v-model:show="showModal">
<slot name="default">
<n-card hoverable size="small">
<div class="list-content">
<!-- 顶部按钮 -->
<n-space class="list-content-top">
<AppleControlBtn
:narrow="true"
:hidden="['close']"
@remove="closeHandle"
/>
</n-space>
<!-- 中间 -->
<div class="list-content-img">
<img
:src="requireUrl('.', '20211219181327.png')"
:alt="cardData?.title"
/>
</div>
</div>
<template #action>
<n-space class="list-footer" justify="space-between">
<n-text>
{{ cardData?.title || '' }}
</n-text>
<!-- 工具 -->
<n-space>
<n-text>
<n-badge
class="animation-twinkle"
dot
:color="cardData?.release ? '#34c749' : '#fcbc40'"
/>
{{ cardData?.release ? '已发布' : '未发布' }}
</n-text>
<template v-for="item in fnBtnList" :key="item.key">
<n-tooltip placement="bottom" trigger="hover">
<template #trigger>
<n-button size="small">
<template #icon>
<component :is="item.icon" />
</template>
</n-button>
</template>
<span> {{ item.label }}</span>
</n-tooltip>
</template>
</n-space>
<!-- end -->
</n-space>
</template>
</n-card>
</slot>
</n-modal>
</template>
<script setup lang="ts">
import { renderIcon } from '@/utils/index'
import { icon } from '@/plugins'
import { AppleControlBtn } from '@/components/AppleControlBtn'
const { HammerIcon } = icon.ionicons5
const emit = defineEmits(['close'])
const props = defineProps({
modalShow: Boolean,
cardData: Object
})
const handleSelect = (key: string) => {
console.log(key)
}
const requireUrl = (path: string, name: string) => {
return new URL(`${path}/${name}`, import.meta.url).href
}
const fnBtnList = [
{
label: '编辑',
key: 'edit',
icon: renderIcon(HammerIcon)
}
]
//
const resizeHandle = () => {}
//
const closeHandle = () => {
emit('close')
}
</script>
<style lang="scss" scoped>
$padding: 30px;
$contentHeight: calc(80vh);
@include go('modal-card') {
position: relative;
width: 82vw;
.list-content {
margin-top: 20px;
border-radius: $--border-radius-base;
overflow: hidden;
@include background-point('background-point');
@extend .go-point-bg;
&-top {
position: absolute;
top: 10px;
left: 10px;
height: 22px;
}
&-img {
@extend .go-flex-center;
img {
height: $contentHeight;
@extend .go-border-radius;
}
}
}
.list-footer {
line-height: 30px;
}
}
</style>

@ -1,6 +1,6 @@
<template>
<n-layout-sider
class="go-project-layout-sider"
class="go-project-sider"
bordered
collapse-mode="width"
show-trigger="bar"
@ -68,6 +68,7 @@ $siderHeight: 100vh;
@include go(project) {
&-sider {
@include filter-bg-color('aside-background_color');
&-top {
display: flex;
align-items: center;

@ -3,3 +3,5 @@ declare module '*.vue' {
const component: DefineComponent<{}, {}, any>
export default component
}
declare module 'lodash'