初始版本提交
This commit is contained in:
13
src/views/demo/feat/breadcrumb/ChildrenList.vue
Normal file
13
src/views/demo/feat/breadcrumb/ChildrenList.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<PageWrapper title="层级面包屑示例" content="子级页面面包屑会添加到当前层级后面">
|
||||
<router-link to="/feat/breadcrumb/children/childrenDetail"> 进入子级详情页 </router-link>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { PageWrapper },
|
||||
});
|
||||
</script>
|
||||
10
src/views/demo/feat/breadcrumb/ChildrenListDetail.vue
Normal file
10
src/views/demo/feat/breadcrumb/ChildrenListDetail.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<PageWrapper title="子级详情页">
|
||||
<div>子级详情页内容在此</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
export default defineComponent({ components: { PageWrapper } });
|
||||
</script>
|
||||
13
src/views/demo/feat/breadcrumb/FlatList.vue
Normal file
13
src/views/demo/feat/breadcrumb/FlatList.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<PageWrapper title="平级面包屑示例" content="子级页面面包屑会覆盖当前层级">
|
||||
<router-link to="/feat/breadcrumb/flatDetail"> 进入平级详情页 </router-link>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { PageWrapper },
|
||||
});
|
||||
</script>
|
||||
8
src/views/demo/feat/breadcrumb/FlatListDetail.vue
Normal file
8
src/views/demo/feat/breadcrumb/FlatListDetail.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div>平级详情页</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({});
|
||||
</script>
|
||||
43
src/views/demo/feat/click-out-side/index.vue
Normal file
43
src/views/demo/feat/click-out-side/index.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<PageWrapper title="点内外部触发事件">
|
||||
<ClickOutSide @click-outside="handleClickOutside" class="flex justify-center">
|
||||
<div @click="innerClick" class="demo-box">
|
||||
{{ text }}
|
||||
</div>
|
||||
</ClickOutSide>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { ClickOutSide } from '/@/components/ClickOutSide';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { ClickOutSide, PageWrapper },
|
||||
setup() {
|
||||
const text = ref('Click');
|
||||
function handleClickOutside() {
|
||||
text.value = 'Click Out Side';
|
||||
}
|
||||
|
||||
function innerClick() {
|
||||
text.value = 'Click Inner';
|
||||
}
|
||||
return { innerClick, handleClickOutside, text };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.demo-box {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
background-color: #408ede;
|
||||
border-radius: 10px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
85
src/views/demo/feat/context-menu/index.vue
Normal file
85
src/views/demo/feat/context-menu/index.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<PageWrapper title="右键菜单示例">
|
||||
<CollapseContainer title="Simple">
|
||||
<a-button type="primary" @contextmenu="handleContext"> Right Click on me </a-button>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="Multiple" class="mt-4">
|
||||
<a-button type="primary" @contextmenu="handleMultipleContext"> Right Click on me </a-button>
|
||||
</CollapseContainer>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { useContextMenu } from '/@/hooks/web/useContextMenu';
|
||||
import { CollapseContainer } from '/@/components/Container';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { CollapseContainer, PageWrapper },
|
||||
setup() {
|
||||
const [createContextMenu] = useContextMenu();
|
||||
const { createMessage } = useMessage();
|
||||
function handleContext(e: MouseEvent) {
|
||||
createContextMenu({
|
||||
event: e,
|
||||
items: [
|
||||
{
|
||||
label: 'New',
|
||||
icon: 'bi:plus',
|
||||
handler: () => {
|
||||
createMessage.success('click new');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Open',
|
||||
icon: 'bx:bxs-folder-open',
|
||||
handler: () => {
|
||||
createMessage.success('click open');
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function handleMultipleContext(e: MouseEvent) {
|
||||
createContextMenu({
|
||||
event: e,
|
||||
items: [
|
||||
{
|
||||
label: 'New',
|
||||
icon: 'bi:plus',
|
||||
|
||||
children: [
|
||||
{
|
||||
label: 'New1-1',
|
||||
icon: 'bi:plus',
|
||||
divider: true,
|
||||
children: [
|
||||
{
|
||||
label: 'New1-1-1',
|
||||
handler: () => {
|
||||
createMessage.success('click new');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'New1-2-1',
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'New1-2',
|
||||
icon: 'bi:plus',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
return { handleContext, handleMultipleContext };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
40
src/views/demo/feat/copy/index.vue
Normal file
40
src/views/demo/feat/copy/index.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<PageWrapper title="文本复制示例">
|
||||
<CollapseContainer class="w-full h-32 bg-white rounded-md" title="Copy Example">
|
||||
<div class="flex justify-center">
|
||||
<a-input placeholder="请输入" v-model:value="value" />
|
||||
<a-button type="primary" @click="handleCopy"> Copy </a-button>
|
||||
</div>
|
||||
</CollapseContainer>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, unref, ref } from 'vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Copy',
|
||||
components: { CollapseContainer, PageWrapper },
|
||||
setup() {
|
||||
const valueRef = ref('');
|
||||
const { createMessage } = useMessage();
|
||||
const { clipboardRef, copiedRef } = useCopyToClipboard();
|
||||
|
||||
function handleCopy() {
|
||||
const value = unref(valueRef);
|
||||
if (!value) {
|
||||
createMessage.warning('请输入要拷贝的内容!');
|
||||
return;
|
||||
}
|
||||
clipboardRef.value = value;
|
||||
if (unref(copiedRef)) {
|
||||
createMessage.warning('copy success!');
|
||||
}
|
||||
}
|
||||
return { handleCopy, value: valueRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
1
src/views/demo/feat/download/imgBase64.ts
Normal file
1
src/views/demo/feat/download/imgBase64.ts
Normal file
File diff suppressed because one or more lines are too long
66
src/views/demo/feat/download/index.vue
Normal file
66
src/views/demo/feat/download/index.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<PageWrapper title="文件下载示例">
|
||||
<a-alert message="根据后台接口文件流下载" />
|
||||
<a-button type="primary" class="my-4" @click="handleDownByData"> 文件流下载 </a-button>
|
||||
|
||||
<a-alert message="根据文件地址下载文件" />
|
||||
<a-button type="primary" class="my-4" @click="handleDownloadByUrl"> 文件地址下载 </a-button>
|
||||
|
||||
<a-alert message="base64流下载" />
|
||||
<a-button type="primary" class="my-4" @click="handleDownloadByBase64"> base64流下载 </a-button>
|
||||
|
||||
<a-alert message="图片Url下载,如果有跨域问题,需要处理图片跨域" />
|
||||
<a-button type="primary" class="my-4" @click="handleDownloadByOnlineUrl">
|
||||
图片Url下载
|
||||
</a-button>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import {
|
||||
downloadByUrl,
|
||||
downloadByData,
|
||||
downloadByBase64,
|
||||
downloadByOnlineUrl,
|
||||
} from '/@/utils/file/download';
|
||||
import imgBase64 from './imgBase64';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Alert } from 'ant-design-vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { PageWrapper, [Alert.name]: Alert },
|
||||
setup() {
|
||||
function handleDownByData() {
|
||||
downloadByData('text content', 'testName.txt');
|
||||
}
|
||||
function handleDownloadByUrl() {
|
||||
downloadByUrl({
|
||||
url: 'https://codeload.github.com/anncwb/vue-vben-admin-doc/zip/master',
|
||||
target: '_self',
|
||||
});
|
||||
|
||||
downloadByUrl({
|
||||
url: 'https://vebn.oss-cn-beijing.aliyuncs.com/vben/logo.png',
|
||||
target: '_self',
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadByBase64() {
|
||||
downloadByBase64(imgBase64, 'logo.png');
|
||||
}
|
||||
|
||||
function handleDownloadByOnlineUrl() {
|
||||
downloadByOnlineUrl(
|
||||
'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5944817f47b8408e9f1442ece49d68ca~tplv-k3u1fbpfcp-watermark.image',
|
||||
'logo.png',
|
||||
);
|
||||
}
|
||||
return {
|
||||
handleDownloadByUrl,
|
||||
handleDownByData,
|
||||
handleDownloadByBase64,
|
||||
handleDownloadByOnlineUrl,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
48
src/views/demo/feat/full-screen/index.vue
Normal file
48
src/views/demo/feat/full-screen/index.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<PageWrapper title="全屏示例">
|
||||
<CollapseContainer class="w-full h-32 bg-white rounded-md" title="Window Full Screen">
|
||||
<a-button type="primary" @click="enter" class="mr-2"> Enter Window Full Screen </a-button>
|
||||
<a-button color="success" @click="toggle" class="mr-2"> Toggle Window Full Screen </a-button>
|
||||
|
||||
<a-button color="error" @click="exit" class="mr-2"> Exit Window Full Screen </a-button>
|
||||
|
||||
Current State: {{ isFullscreen }}
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer class="w-full mt-5 bg-white rounded-md" title="Dom Full Screen">
|
||||
<a-button type="primary" @click="toggleDom" class="mr-2"> Enter Dom Full Screen </a-button>
|
||||
</CollapseContainer>
|
||||
|
||||
<div
|
||||
ref="domRef"
|
||||
class="flex items-center justify-center w-1/2 h-64 mx-auto mt-10 bg-white rounded-md"
|
||||
>
|
||||
<a-button type="primary" @click="toggleDom" class="mr-2"> Exit Dom Full Screen </a-button>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { CollapseContainer, PageWrapper },
|
||||
setup() {
|
||||
const domRef = ref<Nullable<HTMLElement>>(null);
|
||||
const { enter, toggle, exit, isFullscreen } = useFullscreen();
|
||||
|
||||
const { toggle: toggleDom } = useFullscreen(domRef);
|
||||
return {
|
||||
enter,
|
||||
toggleDom,
|
||||
toggle,
|
||||
isFullscreen,
|
||||
exit,
|
||||
domRef,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
96
src/views/demo/feat/icon/index.vue
Normal file
96
src/views/demo/feat/icon/index.vue
Normal file
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<PageWrapper title="Icon组件示例">
|
||||
<CollapseContainer title="Antv Icon使用 (直接按需引入相应组件即可)">
|
||||
<div class="flex justify-around">
|
||||
<GithubFilled :style="{ fontSize: '30px' }" />
|
||||
<QqCircleFilled :style="{ fontSize: '30px' }" />
|
||||
<WechatFilled :style="{ fontSize: '30px' }" />
|
||||
<AlipayCircleFilled :style="{ fontSize: '30px' }" />
|
||||
<IeCircleFilled :style="{ fontSize: '30px' }" />
|
||||
<TaobaoCircleFilled :style="{ fontSize: '30px' }" />
|
||||
<CodepenCircleFilled :style="{ fontSize: '30px' }" />
|
||||
</div>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="IconIfy 组件使用" class="my-5">
|
||||
<div class="flex justify-around flex-wrap">
|
||||
<Icon icon="ion:layers-outline" :size="30" />
|
||||
<Icon icon="ion:bar-chart-outline" :size="30" />
|
||||
<Icon icon="ion:tv-outline" :size="30" />
|
||||
<Icon icon="ion:settings-outline" :size="30" />
|
||||
</div>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="svg 雪碧图" class="my-5">
|
||||
<div class="flex justify-around flex-wrap">
|
||||
<SvgIcon name="test" size="32" />
|
||||
<template v-for="item in 6" :key="item">
|
||||
<SvgIcon :name="`dynamic-avatar-${item}`" size="32" />
|
||||
</template>
|
||||
</div>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="图标选择器(Iconify)" class="my-5">
|
||||
<div class="flex justify-around flex-wrap">
|
||||
<IconPicker />
|
||||
</div>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="图标选择器(Svg)" class="my-5">
|
||||
<div class="flex justify-around flex-wrap">
|
||||
<IconPicker mode="svg" />
|
||||
</div>
|
||||
</CollapseContainer>
|
||||
|
||||
<Alert
|
||||
show-icon
|
||||
message="推荐使用Iconify组件"
|
||||
description="Icon组件基本包含所有的图标,在下面网址内你可以查询到你想要的任何图标。并且打包只会打包所用到的图标。"
|
||||
/>
|
||||
<a-button type="link" @click="toIconify"> Iconify 图标大全 </a-button>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import { Alert } from 'ant-design-vue';
|
||||
import {
|
||||
QqCircleFilled,
|
||||
GithubFilled,
|
||||
WechatFilled,
|
||||
AlipayCircleFilled,
|
||||
IeCircleFilled,
|
||||
TaobaoCircleFilled,
|
||||
CodepenCircleFilled,
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
import { Icon, IconPicker, SvgIcon } from '/@/components/Icon/index';
|
||||
|
||||
import { openWindow } from '/@/utils';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
PageWrapper,
|
||||
CollapseContainer,
|
||||
GithubFilled,
|
||||
QqCircleFilled,
|
||||
WechatFilled,
|
||||
AlipayCircleFilled,
|
||||
IeCircleFilled,
|
||||
TaobaoCircleFilled,
|
||||
CodepenCircleFilled,
|
||||
Icon,
|
||||
Alert,
|
||||
IconPicker,
|
||||
SvgIcon,
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
toIconify: () => {
|
||||
openWindow('https://iconify.design/');
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
31
src/views/demo/feat/img-preview/index.vue
Normal file
31
src/views/demo/feat/img-preview/index.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<PageWrapper title="图片预览示例">
|
||||
<ImagePreview :imageList="imgList" />
|
||||
<a-button @click="openImg" type="primary">无预览图</a-button>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { createImgPreview, ImagePreview } from '/@/components/Preview/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
// import { PreviewActions } from '/@/components/Preview/src/typing';
|
||||
|
||||
const imgList: string[] = [
|
||||
'https://picsum.photos/id/66/346/216',
|
||||
'https://picsum.photos/id/67/346/216',
|
||||
'https://picsum.photos/id/68/346/216',
|
||||
];
|
||||
export default defineComponent({
|
||||
components: { PageWrapper, ImagePreview },
|
||||
setup() {
|
||||
function openImg() {
|
||||
const onImgLoad = ({ index, url, dom }) => {
|
||||
console.log(`第${index + 1}张图片已加载,URL为:${url}`, dom);
|
||||
};
|
||||
// 可以使用createImgPreview返回的 PreviewActions 来控制预览逻辑,实现类似幻灯片、自动旋转之类的骚操作
|
||||
createImgPreview({ imageList: imgList, defaultWidth: 700, rememberState: true, onImgLoad });
|
||||
}
|
||||
return { imgList, openImg };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
42
src/views/demo/feat/menu-params/index.vue
Normal file
42
src/views/demo/feat/menu-params/index.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<PageWrapper title="带参数菜单(路由)" content="支持多级参数">
|
||||
当前参数:{{ params }}
|
||||
<br />
|
||||
输入参数切换路由:
|
||||
<Input v-model:value="value" placeholder="建议为url标准字符,输入后点击切换" />
|
||||
<a-button type="primary" @click="handleClickGo">切换路由</a-button>
|
||||
<br />
|
||||
切换路由后
|
||||
<ul>
|
||||
<li>可刷新页面测试路由参数情况是否正常。</li>
|
||||
<li>可于左侧菜单中展开子菜单,点击测试参数是否携带正常。</li>
|
||||
</ul>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Input } from 'ant-design-vue';
|
||||
import { computed, defineComponent, ref, unref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TestMenu',
|
||||
components: { PageWrapper, Input },
|
||||
setup() {
|
||||
const { currentRoute, replace } = useRouter();
|
||||
const value = ref<string>('');
|
||||
|
||||
const handleClickGo = () => {
|
||||
const { name } = unref(currentRoute);
|
||||
replace({ name: name!, params: { id: unref(value) } });
|
||||
};
|
||||
return {
|
||||
value,
|
||||
handleClickGo,
|
||||
params: computed(() => {
|
||||
return unref(currentRoute).params;
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
100
src/views/demo/feat/msg/index.vue
Normal file
100
src/views/demo/feat/msg/index.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<PageWrapper title="消息示例">
|
||||
<CollapseContainer class="w-full h-32 bg-white rounded-md" title="Message">
|
||||
<a-button @click="infoMsg('Info message')" class="mr-2"> Info </a-button>
|
||||
<a-button @click="successMsg('Success message')" class="mr-2" color="success">
|
||||
Success
|
||||
</a-button>
|
||||
<a-button @click="warningMsg('Warning message')" class="mr-2" color="warning">
|
||||
Warning
|
||||
</a-button>
|
||||
<a-button @click="errorMsg('Error message')" class="mr-2" color="error"> Error </a-button>
|
||||
<a-button @click="handleLoading" class="mr-2" type="primary"> Loading </a-button>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer class="w-full h-32 mt-5 bg-white rounded-md" title="Comfirm">
|
||||
<a-button @click="handleConfirm('info')" class="mr-2"> Info </a-button>
|
||||
<a-button @click="handleConfirm('warning')" color="warning" class="mr-2"> Warning </a-button>
|
||||
<a-button @click="handleConfirm('success')" color="success" class="mr-2"> Success </a-button>
|
||||
<a-button @click="handleConfirm('error')" color="error" class="mr-2"> Error </a-button>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer class="w-full h-32 mt-5 bg-white rounded-md" title="Modal">
|
||||
<a-button @click="handleInfoModal" class="mr-2"> Info </a-button>
|
||||
<a-button @click="handleSuccessModal" color="success" class="mr-2"> Success </a-button>
|
||||
<a-button @click="handleErrorModal" color="error" class="mr-2"> Error </a-button>
|
||||
<a-button @click="handleWarningModal" color="warning" class="mr-2"> Warning </a-button>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer
|
||||
class="w-full h-32 mt-5 bg-white rounded-md"
|
||||
title="Notification 用法与上面一致"
|
||||
>
|
||||
<a-button @click="handleNotify" color="success" class="mr-2"> Success </a-button>
|
||||
</CollapseContainer>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { CollapseContainer, PageWrapper },
|
||||
setup() {
|
||||
const {
|
||||
createMessage,
|
||||
createConfirm,
|
||||
createSuccessModal,
|
||||
createInfoModal,
|
||||
createErrorModal,
|
||||
createWarningModal,
|
||||
notification,
|
||||
} = useMessage();
|
||||
const { info, success, warning, error } = createMessage;
|
||||
|
||||
function handleLoading() {
|
||||
createMessage.loading('Loading...');
|
||||
}
|
||||
function handleConfirm(type: 'warning' | 'error' | 'success' | 'info') {
|
||||
createConfirm({
|
||||
iconType: type,
|
||||
title: 'Tip',
|
||||
content: 'content message...',
|
||||
});
|
||||
}
|
||||
function handleSuccessModal() {
|
||||
createSuccessModal({ title: 'Tip', content: 'content message...' });
|
||||
}
|
||||
function handleErrorModal() {
|
||||
createErrorModal({ title: 'Tip', content: 'content message...' });
|
||||
}
|
||||
function handleWarningModal() {
|
||||
createWarningModal({ title: 'Tip', content: 'content message...' });
|
||||
}
|
||||
function handleInfoModal() {
|
||||
createInfoModal({ title: 'Tip', content: 'content message...' });
|
||||
}
|
||||
function handleNotify() {
|
||||
notification.success({
|
||||
message: 'Tip',
|
||||
description: 'content message...',
|
||||
});
|
||||
}
|
||||
return {
|
||||
infoMsg: info,
|
||||
successMsg: success,
|
||||
warningMsg: warning,
|
||||
errorMsg: error,
|
||||
handleLoading,
|
||||
handleConfirm,
|
||||
handleSuccessModal,
|
||||
handleErrorModal,
|
||||
handleWarningModal,
|
||||
handleInfoModal,
|
||||
handleNotify,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
49
src/views/demo/feat/print/index.vue
Normal file
49
src/views/demo/feat/print/index.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<PageWrapper title="打印示例">
|
||||
<CollapseContainer title="json打印表格">
|
||||
<a-button type="primary" @click="jsonPrint">打印</a-button>
|
||||
</CollapseContainer>
|
||||
|
||||
<a-button type="primary" class="mt-5" @click="imagePrint">Image Print</a-button>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
|
||||
import printJS from 'print-js';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AppLogo',
|
||||
components: { PageWrapper, CollapseContainer },
|
||||
setup() {
|
||||
function jsonPrint() {
|
||||
printJS({
|
||||
printable: [
|
||||
{ name: 'll', email: '123@gmail.com', phone: '123' },
|
||||
{ name: 'qq', email: '456@gmail.com', phone: '456' },
|
||||
],
|
||||
properties: ['name', 'email', 'phone'],
|
||||
type: 'json',
|
||||
});
|
||||
}
|
||||
|
||||
function imagePrint() {
|
||||
printJS({
|
||||
printable: [
|
||||
'https://anncwb.github.io/anncwb/images/preview1.png',
|
||||
'https://anncwb.github.io/anncwb/images/preview2.png',
|
||||
],
|
||||
type: 'image',
|
||||
header: 'Multiple Images',
|
||||
imageStyle: 'width:100%;',
|
||||
});
|
||||
}
|
||||
return {
|
||||
jsonPrint,
|
||||
imagePrint,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
23
src/views/demo/feat/request-demo/index.vue
Normal file
23
src/views/demo/feat/request-demo/index.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="request-box">
|
||||
<a-button @click="handleClick" type="primary"> 点击会重新发起请求5次 </a-button>
|
||||
<p>打开浏览器的network面板,可以看到发出了六次请求</p>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { testRetry } from '/@/api/system/login';
|
||||
// @ts-ignore
|
||||
const handleClick = async () => {
|
||||
await testRetry();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.request-box {
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
31
src/views/demo/feat/ripple/index.vue
Normal file
31
src/views/demo/feat/ripple/index.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<PageWrapper title="Ripple示例">
|
||||
<div class="demo-box" v-ripple>content</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import RippleDirective from '/@/directives/ripple';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { PageWrapper },
|
||||
directives: {
|
||||
Ripple: RippleDirective,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.demo-box {
|
||||
display: flex;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
background-color: #408ede;
|
||||
border-radius: 10px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
54
src/views/demo/feat/session-timeout/index.vue
Normal file
54
src/views/demo/feat/session-timeout/index.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<PageWrapper
|
||||
title="登录过期示例"
|
||||
content="用户登录过期示例,不再跳转登录页,直接生成页面覆盖当前页面,方便保持过期前的用户状态!"
|
||||
>
|
||||
<a-card title="请点击下面的按钮访问测试接口" extra="所访问的接口会返回Token过期响应">
|
||||
<a-card-grid style="width: 50%; text-align: center">
|
||||
<a-button type="primary" @click="test1">HttpStatus == 401</a-button>
|
||||
</a-card-grid>
|
||||
<a-card-grid style="width: 50%; text-align: center">
|
||||
<span></span>
|
||||
<a-button class="ml-4" type="primary" @click="test2">Response.code == 401</a-button>
|
||||
</a-card-grid>
|
||||
</a-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
|
||||
import { sessionTimeoutApi, tokenExpiredApi } from '/@/api/demo/account';
|
||||
import { Card } from 'ant-design-vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TestSessionTimeout',
|
||||
components: { ACardGrid: Card.Grid, ACard: Card, PageWrapper },
|
||||
setup() {
|
||||
const userStore = useUserStore();
|
||||
async function test1() {
|
||||
// 示例网站生产环境用的是mock数据,不能返回Http状态码,
|
||||
// 所以在生产环境直接改变状态来达到测试效果
|
||||
if (import.meta.env.PROD) {
|
||||
userStore.setToken(undefined);
|
||||
userStore.setSessionTimeout(true);
|
||||
} else {
|
||||
// 这个api会返回状态码为401的响应
|
||||
await sessionTimeoutApi();
|
||||
}
|
||||
}
|
||||
|
||||
async function test2() {
|
||||
// 这个api会返回code为401的json数据,Http状态码为200
|
||||
try {
|
||||
await tokenExpiredApi();
|
||||
} catch (err) {
|
||||
console.log('接口访问错误:', (err as Error).message || '错误');
|
||||
}
|
||||
}
|
||||
|
||||
return { test1, test2 };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
27
src/views/demo/feat/tab-params/index.vue
Normal file
27
src/views/demo/feat/tab-params/index.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<PageWrapper title="带参数标签页" content="支持带参数多tab缓存">
|
||||
Current Param : {{ params }}
|
||||
<br />
|
||||
Keep Alive
|
||||
<Input />
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, unref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Input } from 'ant-design-vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TestTab',
|
||||
components: { PageWrapper, Input },
|
||||
setup() {
|
||||
const { currentRoute } = useRouter();
|
||||
return {
|
||||
params: computed(() => {
|
||||
return unref(currentRoute).params;
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
28
src/views/demo/feat/tabs/TabDetail.vue
Normal file
28
src/views/demo/feat/tabs/TabDetail.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<PageWrapper title="Tab详情页面">
|
||||
<div>{{ index }} - 详情页内容在此</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { useTabs } from '/@/hooks/web/useTabs';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TabDetail',
|
||||
components: { PageWrapper },
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const index = route.params?.id ?? -1;
|
||||
const { setTitle } = useTabs();
|
||||
|
||||
// 设置标识
|
||||
setTitle(`No.${index} - 详情信息`);
|
||||
return {
|
||||
index,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
69
src/views/demo/feat/tabs/index.vue
Normal file
69
src/views/demo/feat/tabs/index.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<PageWrapper title="标签页操作示例">
|
||||
<CollapseContainer title="在下面输入框输入文本,切换后回来内容会保存">
|
||||
<a-alert banner message="该操作不会影响页面标题,仅修改Tab标题" />
|
||||
<div class="mt-2 flex flex-grow-0">
|
||||
<a-button class="mr-2" @click="setTabTitle" type="primary"> 设置Tab标题 </a-button>
|
||||
<a-input placeholder="请输入" v-model:value="title" class="mr-4 w-12" />
|
||||
</div>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer class="mt-4" title="标签页操作">
|
||||
<a-button class="mr-2" @click="closeAll"> 关闭所有 </a-button>
|
||||
<a-button class="mr-2" @click="closeLeft"> 关闭左侧 </a-button>
|
||||
<a-button class="mr-2" @click="closeRight"> 关闭右侧 </a-button>
|
||||
<a-button class="mr-2" @click="closeOther"> 关闭其他 </a-button>
|
||||
<a-button class="mr-2" @click="closeCurrent"> 关闭当前 </a-button>
|
||||
<a-button class="mr-2" @click="refreshPage"> 刷新当前 </a-button>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer class="mt-4" title="标签页复用超出限制自动关闭(使用场景: 动态路由)">
|
||||
<a-button v-for="index in 6" :key="index" class="mr-2" @click="toDetail(index)">
|
||||
打开{{ index }}详情页
|
||||
</a-button>
|
||||
</CollapseContainer>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { CollapseContainer } from '/@/components/Container';
|
||||
import { useTabs } from '/@/hooks/web/useTabs';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Input, Alert } from 'ant-design-vue';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TabsDemo',
|
||||
components: { CollapseContainer, PageWrapper, [Input.name]: Input, [Alert.name]: Alert },
|
||||
setup() {
|
||||
const go = useGo();
|
||||
const title = ref<string>('');
|
||||
const { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage, setTitle } =
|
||||
useTabs();
|
||||
const { createMessage } = useMessage();
|
||||
function setTabTitle() {
|
||||
if (title.value) {
|
||||
setTitle(title.value);
|
||||
} else {
|
||||
createMessage.error('请输入要设置的Tab标题!');
|
||||
}
|
||||
}
|
||||
|
||||
function toDetail(index: number) {
|
||||
go(`/feat/tabs/detail/${index}`);
|
||||
}
|
||||
return {
|
||||
closeAll,
|
||||
closeLeft,
|
||||
closeRight,
|
||||
closeOther,
|
||||
closeCurrent,
|
||||
toDetail,
|
||||
refreshPage,
|
||||
setTabTitle,
|
||||
title,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
32
src/views/demo/feat/watermark/index.vue
Normal file
32
src/views/demo/feat/watermark/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<PageWrapper title="水印示例">
|
||||
<CollapseContainer class="w-full h-32 bg-white rounded-md" title="Global WaterMark">
|
||||
<a-button type="primary" class="mr-2" @click="setWatermark('WaterMark Info')">
|
||||
Create
|
||||
</a-button>
|
||||
<a-button color="error" class="mr-2" @click="clear"> Clear </a-button>
|
||||
<a-button color="warning" class="mr-2" @click="setWatermark('WaterMark Info New')">
|
||||
Reset
|
||||
</a-button>
|
||||
</CollapseContainer>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import { useWatermark } from '/@/hooks/web/useWatermark';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { CollapseContainer, PageWrapper },
|
||||
setup() {
|
||||
const areaRef = ref<Nullable<HTMLElement>>(null);
|
||||
const { setWatermark, clear } = useWatermark();
|
||||
return {
|
||||
setWatermark,
|
||||
clear,
|
||||
areaRef,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
127
src/views/demo/feat/ws/index.vue
Normal file
127
src/views/demo/feat/ws/index.vue
Normal file
@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<PageWrapper title="WebSocket 示例">
|
||||
<div class="flex">
|
||||
<div class="w-1/3 bg-white p-4">
|
||||
<div class="flex items-center">
|
||||
<span class="text-lg font-medium mr-4"> 连接状态: </span>
|
||||
<Tag :color="getTagColor">{{ status }}</Tag>
|
||||
</div>
|
||||
<hr class="my-4" />
|
||||
|
||||
<div class="flex">
|
||||
<a-input v-model:value="server" disabled>
|
||||
<template #addonBefore> 服务地址 </template>
|
||||
</a-input>
|
||||
<a-button :type="getIsOpen ? 'danger' : 'primary'" @click="toggle">
|
||||
{{ getIsOpen ? '关闭连接' : '开启连接' }}
|
||||
</a-button>
|
||||
</div>
|
||||
<p class="text-lg font-medium mt-4">设置</p>
|
||||
<hr class="my-4" />
|
||||
|
||||
<InputTextArea
|
||||
placeholder="需要发送到服务器的内容"
|
||||
:disabled="!getIsOpen"
|
||||
v-model:value="sendValue"
|
||||
allowClear
|
||||
/>
|
||||
|
||||
<a-button type="primary" block class="mt-4" :disabled="!getIsOpen" @click="handlerSend">
|
||||
发送
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<div class="w-2/3 bg-white ml-4 p-4">
|
||||
<span class="text-lg font-medium mr-4"> 消息记录: </span>
|
||||
<hr class="my-4" />
|
||||
|
||||
<div class="max-h-80 overflow-auto">
|
||||
<ul>
|
||||
<li v-for="item in getList" class="mt-2" :key="item.time">
|
||||
<div class="flex items-center">
|
||||
<span class="mr-2 text-primary font-medium">收到消息:</span>
|
||||
<span>{{ formatToDateTime(item.time) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
{{ item.res }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, watchEffect, computed, toRefs } from 'vue';
|
||||
import { Tag, Input } from 'ant-design-vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { useWebSocket } from '@vueuse/core';
|
||||
import { formatToDateTime } from '/@/utils/dateUtil';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
PageWrapper,
|
||||
[Input.name]: Input,
|
||||
InputTextArea: Input.TextArea,
|
||||
Tag,
|
||||
},
|
||||
setup() {
|
||||
const state = reactive({
|
||||
server: 'ws://localhost:3300/test',
|
||||
sendValue: '',
|
||||
recordList: [] as { id: number; time: number; res: string }[],
|
||||
});
|
||||
|
||||
const { status, data, send, close, open } = useWebSocket(state.server, {
|
||||
autoReconnect: false,
|
||||
heartbeat: true,
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
if (data.value) {
|
||||
try {
|
||||
const res = JSON.parse(data.value);
|
||||
state.recordList.push(res);
|
||||
} catch (error) {
|
||||
state.recordList.push({
|
||||
res: data.value,
|
||||
id: Math.ceil(Math.random() * 1000),
|
||||
time: new Date().getTime(),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const getIsOpen = computed(() => status.value === 'OPEN');
|
||||
const getTagColor = computed(() => (getIsOpen.value ? 'success' : 'red'));
|
||||
|
||||
const getList = computed(() => {
|
||||
return [...state.recordList].reverse();
|
||||
});
|
||||
|
||||
function handlerSend() {
|
||||
send(state.sendValue);
|
||||
state.sendValue = '';
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (getIsOpen.value) {
|
||||
close();
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
}
|
||||
return {
|
||||
status,
|
||||
formatToDateTime,
|
||||
...toRefs(state),
|
||||
handlerSend,
|
||||
getList,
|
||||
toggle,
|
||||
getIsOpen,
|
||||
getTagColor,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user