Merge branch 'main' of github.com:pure-admin/vue-pure-admin into gitee
@ -1,6 +1,6 @@
|
||||
# 预发布也需要生产环境的行为
|
||||
# https://cn.vitejs.dev/guide/env-and-mode.html#modes
|
||||
NODE_ENV=production
|
||||
# NODE_ENV = development
|
||||
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
||||
|
12
.vscode/vue3.0.code-snippets
vendored
@ -1,19 +1,19 @@
|
||||
{
|
||||
"Vue3.0快速生成模板": {
|
||||
"scope": "vue",
|
||||
"prefix": "Vue3.0",
|
||||
"body": [
|
||||
"<template>",
|
||||
"\t<div>\n",
|
||||
"\t</div>",
|
||||
"\t<div>test</div>",
|
||||
"</template>\n",
|
||||
"<script lang='ts'>",
|
||||
"export default {",
|
||||
"\tsetup(){",
|
||||
"\t\treturn{\n\n\t\t}",
|
||||
"\t},",
|
||||
"\tsetup() {",
|
||||
"\t\treturn {}",
|
||||
"\t}",
|
||||
"}",
|
||||
"</script>\n",
|
||||
"<style scoped>\n",
|
||||
"<style lang='scss' scoped>\n",
|
||||
"</style>",
|
||||
"$2"
|
||||
],
|
||||
|
6
.vscode/vue3.2.code-snippets
vendored
@ -1,14 +1,14 @@
|
||||
{
|
||||
"Vue3.2+快速生成模板": {
|
||||
"scope": "vue",
|
||||
"prefix": "Vue3.2+",
|
||||
"body": [
|
||||
"<script setup lang='ts'>",
|
||||
"</script>\n",
|
||||
"<template>",
|
||||
"\t<div>\n",
|
||||
"\t</div>",
|
||||
"\t<div>test</div>",
|
||||
"</template>\n",
|
||||
"<style scoped>\n",
|
||||
"<style lang='scss' scoped>\n",
|
||||
"</style>",
|
||||
"$2"
|
||||
],
|
||||
|
20
.vscode/vue3.3.code-snippets
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"Vue3.3+defineOptions快速生成模板": {
|
||||
"scope": "vue",
|
||||
"prefix": "Vue3.3+",
|
||||
"body": [
|
||||
"<script setup lang='ts'>",
|
||||
"defineOptions({",
|
||||
"\tname: ''",
|
||||
"})",
|
||||
"</script>\n",
|
||||
"<template>",
|
||||
"\t<div>test</div>",
|
||||
"</template>\n",
|
||||
"<style lang='scss' scoped>\n",
|
||||
"</style>",
|
||||
"$2"
|
||||
],
|
||||
"description": "Vue3.3+defineOptions快速生成模板"
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ The simplified version is based on the shelf extracted from [vue-pure-admin](htt
|
||||
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1kg411v7QT)
|
||||
- [Click Watch UI Design](https://www.bilibili.com/video/BV17g411T7rq)
|
||||
|
||||
## Docs (support `PWA` fast, offline access)
|
||||
## Docs
|
||||
|
||||
- [Click me to view the domestic documentation site](https://yiming_chang.gitee.io/pure-admin-doc)
|
||||
- [Click me to view foreign document site](https://pure-admin.github.io/pure-admin-doc)
|
||||
@ -140,34 +140,12 @@ Support modern browsers, not IE
|
||||
|
||||
[xiaoxian521](https://github.com/xiaoxian521)、[Ten-K](https://github.com/Ten-K)
|
||||
|
||||
## Donate
|
||||
|
||||
If you think this project is helpful to you, you can help the author buy a glass of juice 🍹 Show your support
|
||||
|
||||
<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f69bf13c5b854ed5b699807cafa0e3ce~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?" width="150px" height="150px" />
|
||||
|
||||
## License
|
||||
|
||||
In principle, no fees and copyrights are charged, and you can use it with confidence, but if you need secondary open source, please contact the author for permission!
|
||||
In principle, no fees and copyrights are charged, and it is commercially available, but if you need secondary open source (such as using this platform for secondary development and open source, the front-end code must be open source and free), please contact the author for permission! (Free, just take a record)
|
||||
|
||||
[MIT © 2020-present, pure-admin](./LICENSE)
|
||||
|
||||
## Backers
|
||||
|
||||
Thank you very much for your support, I believe the project will get better and better :heart:
|
||||
|
||||
| xueyuheng | taolei1990 | hang-kim | madwolfcrazy | limuen | BenLakes |
|
||||
| :--------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| <a href="https://github.com/xueyuheng"><img src="https://avatars.githubusercontent.com/u/48202935?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/taolei1990"><img src="https://avatars.githubusercontent.com/u/23173640?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/hang-kim"><img src="https://avatars.githubusercontent.com/u/52914259?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/madwolfcrazy"><img src="https://avatars.githubusercontent.com/u/223671?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/limuen"><img src="https://avatars.githubusercontent.com/u/31790606?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/BenLakes"><img src="https://avatars.githubusercontent.com/u/15206046?v=4" width="60px" height="60px" /></a> |
|
||||
| mollerzhu | TLovers | cnyyk | | | |
|
||||
| <a href="https://github.com/mollerzhu"><img src="https://avatars.githubusercontent.com/u/49627902?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/TLovers"><img src="https://avatars.githubusercontent.com/u/26561694?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/cnyyk"><img src="https://avatars.githubusercontent.com/u/275233?v=4" width="60px" height="60px" /></a> | | | |
|
||||
|
||||
## Contributors
|
||||
|
||||
Thanks to all the people who contribute :heart:
|
||||
|
||||
<a href="https://github.com/pure-admin/vue-pure-admin/graphs/contributors"><img src="https://contrib.rocks/image?repo=pure-admin/vue-pure-admin" /></a>
|
||||
|
||||
## `Star`
|
||||
|
||||
Many thanks to the kind individuals who leave a star. Your support is much appreciated :heart:
|
||||
|
30
README.md
@ -22,7 +22,7 @@
|
||||
- [点我查看快速开发教程](https://www.bilibili.com/video/BV1kg411v7QT)
|
||||
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
|
||||
|
||||
## 配套保姆级文档(支持 `PWA` 快速、离线访问)
|
||||
## 配套保姆级文档
|
||||
|
||||
- [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc)
|
||||
- [点我查看国外文档站](https://pure-admin.github.io/pure-admin-doc)
|
||||
@ -140,38 +140,12 @@ pnpm build
|
||||
|
||||
[xiaoxian521](https://github.com/xiaoxian521)、[Ten-K](https://github.com/Ten-K)
|
||||
|
||||
## 支持
|
||||
|
||||
如果您觉得这个项目对您有帮助,可以帮作者买一杯果汁 🍹 表示支持
|
||||
|
||||
<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f69bf13c5b854ed5b699807cafa0e3ce~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?" width="150px" height="150px" />
|
||||
|
||||
## `QQ` 交流群
|
||||
|
||||
[点击去加入](https://yiming_chang.gitee.io/pure-admin-doc/pages/support/#qq-%E4%BA%A4%E6%B5%81%E7%BE%A4)
|
||||
|
||||
## 许可证
|
||||
|
||||
原则上不收取任何费用及版权,可以放心使用,不过如需二次开源(比如用此平台二次开发并开源)请联系作者获取许可!
|
||||
原则上不收取任何费用及版权,可商用,不过如需二次开源(比如用此平台二次开发并开源,要求前端代码必须开源免费)请联系作者获取许可!(免费,走个记录而已)
|
||||
|
||||
[MIT © 2020-present, pure-admin](./LICENSE)
|
||||
|
||||
## 支持者
|
||||
|
||||
非常感谢您们的支持,相信项目会越来越好 :heart:
|
||||
|
||||
| xueyuheng | taolei1990 | hang-kim | madwolfcrazy | limuen | BenLakes |
|
||||
| :--------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| <a href="https://github.com/xueyuheng"><img src="https://avatars.githubusercontent.com/u/48202935?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/taolei1990"><img src="https://avatars.githubusercontent.com/u/23173640?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/hang-kim"><img src="https://avatars.githubusercontent.com/u/52914259?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/madwolfcrazy"><img src="https://avatars.githubusercontent.com/u/223671?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/limuen"><img src="https://avatars.githubusercontent.com/u/31790606?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/BenLakes"><img src="https://avatars.githubusercontent.com/u/15206046?v=4" width="60px" height="60px" /></a> |
|
||||
| mollerzhu | TLovers | cnyyk | | | |
|
||||
| <a href="https://github.com/mollerzhu"><img src="https://avatars.githubusercontent.com/u/49627902?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/TLovers"><img src="https://avatars.githubusercontent.com/u/26561694?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/cnyyk"><img src="https://avatars.githubusercontent.com/u/275233?v=4" width="60px" height="60px" /></a> | | | |
|
||||
|
||||
## 贡献者
|
||||
|
||||
感谢所有做出贡献的人 :heart:
|
||||
|
||||
<a href="https://github.com/pure-admin/vue-pure-admin/graphs/contributors"><img src="https://contrib.rocks/image?repo=pure-admin/vue-pure-admin" /></a>
|
||||
|
||||
## `Star`
|
||||
|
||||
非常感谢留下星星的好心人,感谢您的支持 :heart:
|
||||
|
20
package.json
@ -56,7 +56,7 @@
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"path": "^0.12.7",
|
||||
"pinia": "^2.1.1",
|
||||
"pinia": "^2.1.3",
|
||||
"qrcode": "^1.5.3",
|
||||
"qs": "^6.11.1",
|
||||
"responsive-storage": "^2.2.0",
|
||||
@ -69,7 +69,7 @@
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-json-pretty": "^2.2.4",
|
||||
"vue-pdf-embed": "^1.1.6",
|
||||
"vue-router": "^4.2.0",
|
||||
"vue-router": "^4.2.1",
|
||||
"vue-types": "^5.0.3",
|
||||
"vue-virtual-scroller": "2.0.0-beta.7",
|
||||
"vue-waterfall-plugin-next": "^2.2.1",
|
||||
@ -104,9 +104,9 @@
|
||||
"autoprefixer": "^10.4.14",
|
||||
"cloc": "^2.11.0",
|
||||
"cssnano": "^6.0.1",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-vue": "^9.13.0",
|
||||
"eslint-plugin-vue": "^9.14.0",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.2.2",
|
||||
"picocolors": "^1.0.0",
|
||||
@ -114,12 +114,12 @@
|
||||
"postcss-html": "^1.5.0",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-scss": "^4.0.6",
|
||||
"prettier": "^2.8.7",
|
||||
"pretty-quick": "3.1.1",
|
||||
"rimraf": "^5.0.0",
|
||||
"prettier": "^2.8.8",
|
||||
"pretty-quick": "^3.1.3",
|
||||
"rimraf": "^5.0.1",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"sass": "^1.62.1",
|
||||
"sass-loader": "^13.2.2",
|
||||
"sass-loader": "^13.3.0",
|
||||
"stylelint": "^15.6.2",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-recess-order": "^4.0.0",
|
||||
@ -133,9 +133,9 @@
|
||||
"stylelint-scss": "^5.0.0",
|
||||
"svgo": "^3.0.2",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"terser": "^5.17.4",
|
||||
"terser": "^5.17.5",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.3.7",
|
||||
"vite": "^4.3.8",
|
||||
"vite-plugin-cdn-import": "^0.3.5",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
|
8592
pnpm-lock.yaml
generated
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -12,6 +12,7 @@ import type {
|
||||
|
||||
const dialogStore = ref<Array<DialogOptions>>([]);
|
||||
|
||||
/** 打开弹框 */
|
||||
const addDialog = (options: DialogOptions) => {
|
||||
const open = () =>
|
||||
dialogStore.value.push(Object.assign(options, { visible: true }));
|
||||
@ -24,16 +25,40 @@ const addDialog = (options: DialogOptions) => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 关闭弹框 */
|
||||
const closeDialog = (options: DialogOptions, index: number, args?: any) => {
|
||||
dialogStore.value.splice(index, 1);
|
||||
options.closeCallBack && options.closeCallBack({ options, index, args });
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 更改弹框自身属性值
|
||||
* @param value 属性值
|
||||
* @param key 属性,默认`title`
|
||||
* @param index 弹框索引(默认`0`,代表只有一个弹框,对于嵌套弹框要改哪个弹框的属性值就把该弹框索引赋给`index`)
|
||||
*/
|
||||
const updateDialog = (value: any, key = "title", index = 0) => {
|
||||
dialogStore.value[index][key] = value;
|
||||
};
|
||||
|
||||
/** 关闭所有弹框 */
|
||||
const closeAllDialog = () => {
|
||||
dialogStore.value = [];
|
||||
};
|
||||
|
||||
/** 千万别忘了在下面这三处引入并注册下,放心注册,不使用`addDialog`调用就不会被挂载
|
||||
* https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L4
|
||||
* https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L13
|
||||
* https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L18
|
||||
*/
|
||||
const ReDialog = withInstall(reDialog);
|
||||
|
||||
export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions };
|
||||
export { ReDialog, dialogStore, addDialog, closeDialog, closeAllDialog };
|
||||
export {
|
||||
ReDialog,
|
||||
dialogStore,
|
||||
addDialog,
|
||||
closeDialog,
|
||||
updateDialog,
|
||||
closeAllDialog
|
||||
};
|
||||
|
@ -200,9 +200,13 @@ export default defineComponent({
|
||||
|
||||
return () => (
|
||||
<>
|
||||
<div {...attrs} class="w-[99/100] mt-4 px-2 pb-2 bg-bg_color">
|
||||
<div {...attrs} class="w-[99/100] mt-2 px-2 pb-2 bg-bg_color">
|
||||
<div class="flex justify-between w-full h-[60px] p-4">
|
||||
<p class="font-bold truncate">{props.title}</p>
|
||||
{slots?.title ? (
|
||||
slots.title()
|
||||
) : (
|
||||
<p class="font-bold truncate">{props.title}</p>
|
||||
)}
|
||||
<div class="flex items-center justify-around">
|
||||
{slots?.buttons ? (
|
||||
<div class="flex mr-4">{slots.buttons()}</div>
|
||||
|
@ -51,20 +51,21 @@ let startPosX = null;
|
||||
let isHover = false;
|
||||
let ease = "ease-in";
|
||||
|
||||
// eslint-disable-next-line vue/no-setup-props-destructure
|
||||
const { classOption } = props;
|
||||
|
||||
if (classOption["key"] === undefined) {
|
||||
classOption["key"] = 0;
|
||||
if (props.classOption["key"] === undefined) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.classOption["key"] = 0;
|
||||
}
|
||||
|
||||
const wrap = templateRef<HTMLElement | null>(`wrap${classOption["key"]}`, null);
|
||||
const wrap = templateRef<HTMLElement | null>(
|
||||
`wrap${props.classOption["key"]}`,
|
||||
null
|
||||
);
|
||||
const slotList = templateRef<HTMLElement | null>(
|
||||
`slotList${classOption["key"]}`,
|
||||
`slotList${props.classOption["key"]}`,
|
||||
null
|
||||
);
|
||||
const realBox = templateRef<HTMLElement | null>(
|
||||
`realBox${classOption["key"]}`,
|
||||
`realBox${props.classOption["key"]}`,
|
||||
null
|
||||
);
|
||||
|
||||
@ -107,7 +108,7 @@ const defaultOption = computed(() => {
|
||||
|
||||
const options = computed(() => {
|
||||
// @ts-expect-error
|
||||
return copyObj({}, unref(defaultOption), classOption);
|
||||
return copyObj({}, unref(defaultOption), props.classOption);
|
||||
});
|
||||
|
||||
const leftSwitchClass = computed(() => {
|
||||
@ -495,7 +496,7 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :ref="'wrap' + classOption['key']">
|
||||
<div :ref="'wrap' + props.classOption['key']">
|
||||
<div
|
||||
:style="leftSwitch"
|
||||
v-if="navigation"
|
||||
@ -513,7 +514,7 @@ defineExpose({
|
||||
<slot name="right-switch" />
|
||||
</div>
|
||||
<div
|
||||
:ref="'realBox' + classOption['key']"
|
||||
:ref="'realBox' + props.classOption['key']"
|
||||
:style="pos"
|
||||
@mouseenter="enter"
|
||||
@mouseleave="leave"
|
||||
@ -522,7 +523,7 @@ defineExpose({
|
||||
@touchend="touchEnd"
|
||||
@mousewheel.passive="wheel"
|
||||
>
|
||||
<div :ref="'slotList' + classOption['key']" :style="float">
|
||||
<div :ref="'slotList' + props.classOption['key']" :style="float">
|
||||
<slot />
|
||||
</div>
|
||||
<div v-html="copyHtml" :style="float" />
|
||||
|
@ -164,7 +164,7 @@ onKeyStroke("ArrowDown", handleDown);
|
||||
</template>
|
||||
</el-input>
|
||||
<div class="search-result-container">
|
||||
<el-scrollbar ref="scrollbarRef" max-height="600px">
|
||||
<el-scrollbar ref="scrollbarRef" max-height="calc(90vh - 140px)">
|
||||
<el-empty
|
||||
v-if="resultOptions.length === 0"
|
||||
description="暂无搜索结果"
|
||||
|
@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { useResizeObserver } from "@vueuse/core";
|
||||
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
import { ref, computed, getCurrentInstance, onMounted } from "vue";
|
||||
import enterOutlined from "@/assets/svg/enter_outlined.svg?component";
|
||||
import Bookmark2Line from "@iconify-icons/ri/bookmark-2-line";
|
||||
|
||||
@ -26,6 +27,8 @@ interface Emits {
|
||||
(e: "enter"): void;
|
||||
}
|
||||
|
||||
const resultRef = ref();
|
||||
const innerHeight = ref();
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
const emit = defineEmits<Emits>();
|
||||
const instance = getCurrentInstance()!;
|
||||
@ -59,19 +62,32 @@ function handleTo() {
|
||||
emit("enter");
|
||||
}
|
||||
|
||||
function resizeResult() {
|
||||
// el-scrollbar max-height="calc(90vh - 140px)"
|
||||
innerHeight.value = window.innerHeight - window.innerHeight / 10 - 140;
|
||||
}
|
||||
|
||||
useResizeObserver(resultRef, () => {
|
||||
resizeResult();
|
||||
});
|
||||
|
||||
function handleScroll(index: number) {
|
||||
const curInstance = instance?.proxy?.$refs[`resultItemRef${index}`];
|
||||
if (!curInstance) return 0;
|
||||
const curRef = curInstance[0] as ElRef;
|
||||
const scrollTop = curRef.offsetTop + 128; // 128 两个result-item(56px+56px=112px)高度加上下margin(8px+8px=16px)
|
||||
return scrollTop > 600 ? scrollTop - 600 : 0; // 600 el-scrollbar max-height="600px"
|
||||
return scrollTop > innerHeight.value ? scrollTop - innerHeight.value : 0;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
resizeResult();
|
||||
});
|
||||
|
||||
defineExpose({ handleScroll });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="result">
|
||||
<div ref="resultRef" class="result">
|
||||
<div
|
||||
v-for="(item, index) in options"
|
||||
:key="item.path"
|
||||
|
@ -218,7 +218,6 @@ watch($storage, ({ layout }) => {
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
dataThemeChange();
|
||||
/* 初始化项目配置 */
|
||||
nextTick(() => {
|
||||
settings.greyVal &&
|
||||
|
@ -8,7 +8,15 @@ import { useLayout } from "./hooks/useLayout";
|
||||
import { useAppStoreHook } from "@/store/modules/app";
|
||||
import { useSettingStoreHook } from "@/store/modules/settings";
|
||||
import { deviceDetection, useDark, useGlobal } from "@pureadmin/utils";
|
||||
import { h, reactive, computed, onMounted, defineComponent } from "vue";
|
||||
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
|
||||
import {
|
||||
h,
|
||||
reactive,
|
||||
computed,
|
||||
onMounted,
|
||||
onBeforeMount,
|
||||
defineComponent
|
||||
} from "vue";
|
||||
|
||||
import navbar from "./components/navbar.vue";
|
||||
import tag from "./components/tag/index.vue";
|
||||
@ -102,6 +110,10 @@ onMounted(() => {
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
useDataThemeChange().dataThemeChange();
|
||||
});
|
||||
|
||||
const layoutHeader = defineComponent({
|
||||
render() {
|
||||
return h(
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
formatFlatteningRoutes
|
||||
} from "./utils";
|
||||
import { buildHierarchyTree } from "@/utils/tree";
|
||||
import { isUrl, openLink, storageSession } from "@pureadmin/utils";
|
||||
import { isUrl, openLink, storageSession, isAllEmpty } from "@pureadmin/utils";
|
||||
|
||||
import remainingRouter from "./modules/remaining";
|
||||
|
||||
@ -158,11 +158,22 @@ router.beforeEach((to: toRouteType, _from, next) => {
|
||||
getTopMenu(true);
|
||||
// query、params模式路由传参数的标签页不在此处处理
|
||||
if (route && route.meta?.title) {
|
||||
useMultiTagsStoreHook().handleTags("push", {
|
||||
path: route.path,
|
||||
name: route.name,
|
||||
meta: route.meta
|
||||
});
|
||||
if (isAllEmpty(route.parentId) && route.meta?.backstage) {
|
||||
// 此处为动态顶级路由(目录)
|
||||
const { path, name, meta } = route.children[0];
|
||||
useMultiTagsStoreHook().handleTags("push", {
|
||||
path,
|
||||
name,
|
||||
meta
|
||||
});
|
||||
} else {
|
||||
const { path, name, meta } = route;
|
||||
useMultiTagsStoreHook().handleTags("push", {
|
||||
path,
|
||||
name,
|
||||
meta
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
router.push(to.fullPath);
|
||||
|
@ -3,7 +3,7 @@ import { components } from "@/router/enums";
|
||||
|
||||
export default {
|
||||
path: "/components",
|
||||
redirect: "/components/video",
|
||||
redirect: "/components/dialog",
|
||||
meta: {
|
||||
icon: "menu",
|
||||
title: $t("menus.hscomponents"),
|
||||
|
@ -54,14 +54,14 @@ export function useColumns() {
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "QQ交流群",
|
||||
label: "精简版",
|
||||
cellRenderer: () => {
|
||||
return (
|
||||
<a
|
||||
href="https://yiming_chang.gitee.io/pure-admin-doc/pages/support/#qq-%E4%BA%A4%E6%B5%81%E7%BE%A4"
|
||||
href="https://github.com/pure-admin/pure-admin-thin"
|
||||
target="_blank"
|
||||
>
|
||||
<span style="color: var(--el-color-primary)">点击加群</span>
|
||||
<span style="color: var(--el-color-primary)">精简版</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
@ -2,9 +2,14 @@
|
||||
import { useRouter } from "vue-router";
|
||||
import { h, createVNode, ref } from "vue";
|
||||
import { message } from "@/utils/message";
|
||||
import { cloneDeep } from "@pureadmin/utils";
|
||||
import forms, { type FormProps } from "./form.vue";
|
||||
import { addDialog, closeDialog, closeAllDialog } from "@/components/ReDialog";
|
||||
import { cloneDeep, debounce } from "@pureadmin/utils";
|
||||
import {
|
||||
addDialog,
|
||||
closeDialog,
|
||||
updateDialog,
|
||||
closeAllDialog
|
||||
} from "@/components/ReDialog";
|
||||
|
||||
defineOptions({
|
||||
name: "DialogPage"
|
||||
@ -60,13 +65,16 @@ function onStyleClick() {
|
||||
});
|
||||
}
|
||||
|
||||
function onoOpenDelayClick() {
|
||||
addDialog({
|
||||
title: "延时2秒打开弹框",
|
||||
openDelay: 2000,
|
||||
contentRenderer: () => <p>弹框内容-延时2秒打开弹框</p>
|
||||
});
|
||||
}
|
||||
// 添加 600ms 防抖
|
||||
const onoOpenDelayClick = debounce(
|
||||
() =>
|
||||
addDialog({
|
||||
title: "延时2秒打开弹框",
|
||||
openDelay: 2000 - 600,
|
||||
contentRenderer: () => <p>弹框内容-延时2秒打开弹框</p>
|
||||
}),
|
||||
600
|
||||
);
|
||||
|
||||
function onCloseDelayClick() {
|
||||
addDialog({
|
||||
@ -240,6 +248,35 @@ function onNestingClick() {
|
||||
});
|
||||
}
|
||||
|
||||
// 满足在 contentRenderer 内容区更改弹框自身属性值的场景
|
||||
function onUpdateClick() {
|
||||
const curPage = ref(1);
|
||||
addDialog({
|
||||
title: `第${curPage.value}页`,
|
||||
contentRenderer: () => (
|
||||
<>
|
||||
<el-button
|
||||
disabled={curPage.value > 1 ? false : true}
|
||||
onClick={() => {
|
||||
curPage.value -= 1;
|
||||
updateDialog(`第${curPage.value}页`);
|
||||
}}
|
||||
>
|
||||
上一页
|
||||
</el-button>
|
||||
<el-button
|
||||
onClick={() => {
|
||||
curPage.value += 1;
|
||||
updateDialog(`第${curPage.value}页`);
|
||||
}}
|
||||
>
|
||||
下一页
|
||||
</el-button>
|
||||
</>
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
// 结合Form表单(第一种方式,弹框关闭立刻恢复初始值)通过 props 属性接收子组件的 prop 并赋值
|
||||
function onFormOneClick() {
|
||||
addDialog({
|
||||
@ -421,6 +458,7 @@ function onBeforeSureClick() {
|
||||
<el-button @click="onOpenClick"> 打开后的回调 </el-button>
|
||||
<el-button @click="onCloseCallBackClick"> 关闭后的回调 </el-button>
|
||||
<el-button @click="onNestingClick"> 嵌套的弹框 </el-button>
|
||||
<el-button @click="onUpdateClick"> 更改弹框自身属性值 </el-button>
|
||||
</el-space>
|
||||
<el-divider />
|
||||
<el-space wrap>
|
||||
|
56
src/views/editor/components/base.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import "@wangeditor/editor/dist/css/style.css";
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
|
||||
|
||||
defineOptions({
|
||||
name: "BaseEditor"
|
||||
});
|
||||
|
||||
const mode = "default";
|
||||
// 编辑器实例,必须用 shallowRef
|
||||
const editorRef = shallowRef();
|
||||
|
||||
// 内容 HTML
|
||||
const valueHtml = ref("<p>你好</p>");
|
||||
|
||||
// 模拟 ajax 异步获取内容
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
valueHtml.value = "<p>我是模拟的异步数据</p>";
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
const toolbarConfig: any = { excludeKeys: "fullScreen" };
|
||||
const editorConfig = { placeholder: "请输入内容..." };
|
||||
|
||||
const handleCreated = editor => {
|
||||
// 记录 editor 实例,重要!
|
||||
editorRef.value = editor;
|
||||
};
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
if (editor == null) return;
|
||||
editor.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="wangeditor">
|
||||
<Toolbar
|
||||
:editor="editorRef"
|
||||
:defaultConfig="toolbarConfig"
|
||||
:mode="mode"
|
||||
style="border-bottom: 1px solid #ccc"
|
||||
/>
|
||||
<Editor
|
||||
v-model="valueHtml"
|
||||
:defaultConfig="editorConfig"
|
||||
:mode="mode"
|
||||
style="height: 500px; overflow-y: hidden"
|
||||
@onCreated="handleCreated"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
9
src/views/editor/components/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import base from "./base.vue";
|
||||
import multi from "./multi.vue";
|
||||
import picUpload from "./picUpload.vue";
|
||||
|
||||
const Base = base;
|
||||
const Multi = multi;
|
||||
const PicUpload = picUpload;
|
||||
|
||||
export { Base, Multi, PicUpload };
|
76
src/views/editor/components/multi.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<script setup lang="ts">
|
||||
import ReCol from "@/components/ReCol";
|
||||
import { onBeforeUnmount, ref, shallowRef } from "vue";
|
||||
import "@wangeditor/editor/dist/css/style.css";
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
|
||||
defineOptions({
|
||||
name: "MultiEditor"
|
||||
});
|
||||
|
||||
// 模拟后端返回多个编辑器的数据
|
||||
const endEditorList = [
|
||||
{
|
||||
value: "<p>测试一</p>"
|
||||
},
|
||||
{
|
||||
value: "<p>测试二</p>"
|
||||
},
|
||||
{
|
||||
value: "<p>测试三</p>"
|
||||
},
|
||||
{
|
||||
value: "<p>测试四</p>"
|
||||
}
|
||||
];
|
||||
|
||||
// 多个编辑器的情况下,前端必须进行处理,满足 Toolbar 组件的 editor 属性 所需的 shallowRef 格式
|
||||
const editorList = ref([]);
|
||||
endEditorList.forEach(edit => {
|
||||
editorList.value.push({
|
||||
value: edit.value,
|
||||
// 编辑器实例,必须用 shallowRef
|
||||
editorRef: shallowRef()
|
||||
});
|
||||
});
|
||||
|
||||
const mode = "default";
|
||||
|
||||
const toolbarConfig: any = { excludeKeys: "fullScreen" };
|
||||
const editorConfig = { placeholder: "请输入内容..." };
|
||||
|
||||
const handleCreated = (editor, index) => {
|
||||
// 记录 editor 实例,重要!
|
||||
editorList.value[index].editorRef = editor;
|
||||
};
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
return editorList.value.map(edit => {
|
||||
if (edit.editorRef == null) return;
|
||||
edit.editorRef.destroy();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-row :gutter="30" justify="space-around">
|
||||
<re-col :value="11" v-for="(edit, index) in editorList" :key="index">
|
||||
<div class="wangeditor">
|
||||
<Toolbar
|
||||
:editor="edit.editorRef"
|
||||
:defaultConfig="toolbarConfig"
|
||||
:mode="mode"
|
||||
style="border-bottom: 1px solid #ccc"
|
||||
/>
|
||||
<Editor
|
||||
v-model="edit.value"
|
||||
:defaultConfig="editorConfig"
|
||||
:mode="mode"
|
||||
style="height: 300px; overflow-y: hidden"
|
||||
@onCreated="editor => handleCreated(editor, index)"
|
||||
/>
|
||||
</div>
|
||||
</re-col>
|
||||
</el-row>
|
||||
</template>
|
70
src/views/editor/components/picUpload.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, ref, shallowRef } from "vue";
|
||||
import "@wangeditor/editor/dist/css/style.css";
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
|
||||
defineOptions({
|
||||
name: "picUpload"
|
||||
});
|
||||
|
||||
const mode = "default";
|
||||
// 编辑器实例,必须用 shallowRef
|
||||
const editorRef = shallowRef();
|
||||
|
||||
// 内容 HTML
|
||||
const valueHtml = ref(
|
||||
"<p>仅提供代码参考,暂不可上传图片,可根据实际业务改写</p>"
|
||||
);
|
||||
const toolbarConfig: any = { excludeKeys: "fullScreen" };
|
||||
const editorConfig = { placeholder: "请输入内容...", MENU_CONF: {} };
|
||||
|
||||
// 更多详细配置看 https://www.wangeditor.com/v5/menu-config.html#%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87
|
||||
editorConfig.MENU_CONF["uploadImage"] = {
|
||||
// 服务端上传地址,根据实际业务改写
|
||||
server: "",
|
||||
// form-data 的 fieldName,根据实际业务改写
|
||||
fieldName: "file",
|
||||
// 选择文件时的类型限制,根据实际业务改写
|
||||
allowedFileTypes: ["image/png", "image/jpg", "image/jpeg"],
|
||||
// 自定义插入图片
|
||||
customInsert(res: any, insertFn) {
|
||||
// res.data.url是后端返回的图片地址,根据实际业务改写
|
||||
if (res.data.url) {
|
||||
setTimeout(() => {
|
||||
// insertFn插入图片进编辑器
|
||||
insertFn(res.data.url);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreated = editor => {
|
||||
// 记录 editor 实例,重要!
|
||||
editorRef.value = editor;
|
||||
};
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
if (editor == null) return;
|
||||
editor.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="wangeditor">
|
||||
<Toolbar
|
||||
:editor="editorRef"
|
||||
:defaultConfig="toolbarConfig"
|
||||
:mode="mode"
|
||||
style="border-bottom: 1px solid #ccc"
|
||||
/>
|
||||
<Editor
|
||||
v-model="valueHtml"
|
||||
:defaultConfig="editorConfig"
|
||||
:mode="mode"
|
||||
style="height: 500px; overflow-y: hidden"
|
||||
@onCreated="handleCreated"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
@ -1,41 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
|
||||
import Edit from "@iconify-icons/ep/edit";
|
||||
import { ref } from "vue";
|
||||
import { Base, Multi, PicUpload } from "./components";
|
||||
|
||||
defineOptions({
|
||||
name: "Editor"
|
||||
});
|
||||
|
||||
const mode = "default";
|
||||
// 编辑器实例,必须用 shallowRef
|
||||
const editorRef = shallowRef();
|
||||
|
||||
// 内容 HTML
|
||||
const valueHtml = ref("<p>hello</p>");
|
||||
|
||||
// 模拟 ajax 异步获取内容
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
valueHtml.value = "<p>模拟 Ajax 异步设置内容</p>";
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
const toolbarConfig: any = { excludeKeys: "fullScreen" };
|
||||
const editorConfig = { placeholder: "请输入内容..." };
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
if (editor == null) return;
|
||||
editor.destroy();
|
||||
});
|
||||
|
||||
const handleCreated = editor => {
|
||||
editorRef.value = editor; // 记录 editor 实例,重要!
|
||||
};
|
||||
const activeNames = ref(["1"]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -47,7 +18,6 @@ const handleCreated = editor => {
|
||||
<el-link
|
||||
href="https://www.wangeditor.com"
|
||||
target="_blank"
|
||||
:icon="useRenderIcon(Edit)"
|
||||
style="margin: 0 4px 5px; font-size: 16px"
|
||||
>
|
||||
Wangeditor
|
||||
@ -55,20 +25,22 @@ const handleCreated = editor => {
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="wangeditor">
|
||||
<Toolbar
|
||||
style="border-bottom: 1px solid #ccc"
|
||||
:editor="editorRef"
|
||||
:defaultConfig="toolbarConfig"
|
||||
:mode="mode"
|
||||
/>
|
||||
<Editor
|
||||
style="height: 500px; overflow-y: hidden"
|
||||
v-model="valueHtml"
|
||||
:defaultConfig="editorConfig"
|
||||
:mode="mode"
|
||||
@onCreated="handleCreated"
|
||||
/>
|
||||
</div>
|
||||
<el-collapse v-model="activeNames" accordion>
|
||||
<el-collapse-item title="基础用法" name="1">
|
||||
<Base />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="多个富文本" name="2">
|
||||
<Multi />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="自定义图片上传" name="3">
|
||||
<PicUpload />
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-collapse-item__header) {
|
||||
padding-left: 10px;
|
||||
}
|
||||
</style>
|
||||
|