Commit e034d1bacc5501a83188d20129951422bc127e3b

Authored by vben
1 parent 144fde8a

perf: remove optional chain

CHANGELOG.zh_CN.md
1 ## Wip 1 ## Wip
2 2
  3 +### ✨ Features
  4 +
  5 +- 面包屑支持显示图标
  6 +- 新增 tinymce 富文本组件
  7 +
  8 +### 🎫 Chores
  9 +
  10 +- 删除代码内的可选链语法
  11 +
3 ### 🐛 Bug Fixes 12 ### 🐛 Bug Fixes
4 13
5 - 修复抽屉组件自动高度及显示 footer 显示问题 14 - 修复抽屉组件自动高度及显示 footer 显示问题
6 - 修复表单查询后重置回默认值 15 - 修复表单查询后重置回默认值
  16 +- 修复菜单没有子节点时显示折叠的问题
  17 +- 修复面包屑显示样式问题
  18 +- 修复 modal 在 destroyOnClose=true 时多次打开拖拽失效
7 19
8 # 2.0.0-rc.4 (2020-10-21) 20 # 2.0.0-rc.4 (2020-10-21)
9 21
src/components/Authority/index.ts 0 → 100644
  1 +import Authority from './src/index.vue';
  2 +export default Authority;
src/components/Authority/index.tsx renamed to src/components/Authority/src/index.vue
1 -import { defineComponent, PropType, computed, unref } from 'vue'; 1 +<script lang="ts">
  2 + import { defineComponent, PropType, computed, unref } from 'vue';
2 3
3 -import { PermissionModeEnum } from '/@/enums/appEnum';  
4 -import { RoleEnum } from '/@/enums/roleEnum';  
5 -import { usePermission } from '/@/hooks/web/usePermission';  
6 -import { appStore } from '/@/store/modules/app';  
7 -import { getSlot } from '/@/utils/helper/tsxHelper'; 4 + import { PermissionModeEnum } from '/@/enums/appEnum';
  5 + import { RoleEnum } from '/@/enums/roleEnum';
  6 + import { usePermission } from '/@/hooks/web/usePermission';
  7 + import { appStore } from '/@/store/modules/app';
  8 + import { getSlot } from '/@/utils/helper/tsxHelper';
8 9
9 -export default defineComponent({  
10 - name: 'Authority',  
11 - props: {  
12 - // 指定角色可见  
13 - value: {  
14 - type: [Number, Array, String] as PropType<RoleEnum | RoleEnum[]>,  
15 - default: '', 10 + export default defineComponent({
  11 + name: 'Authority',
  12 + props: {
  13 + // 指定角色可见
  14 + value: {
  15 + type: [Number, Array, String] as PropType<RoleEnum | RoleEnum[]>,
  16 + default: '',
  17 + },
16 }, 18 },
17 - },  
18 - setup(props, { slots }) {  
19 - const getModeRef = computed(() => {  
20 - return appStore.getProjectConfig.permissionMode;  
21 - }); 19 + setup(props, { slots }) {
  20 + const getModeRef = computed(() => {
  21 + return appStore.getProjectConfig.permissionMode;
  22 + });
22 23
23 - /**  
24 - * 渲染角色按钮  
25 - */  
26 - function renderRoleAuth() {  
27 - const { value } = props;  
28 - if (!value) {  
29 - return getSlot(slots); 24 + /**
  25 + * 渲染角色按钮
  26 + */
  27 + function renderRoleAuth() {
  28 + const { value } = props;
  29 + if (!value) {
  30 + return getSlot(slots);
  31 + }
  32 + const { hasPermission } = usePermission();
  33 + return hasPermission(value) ? getSlot(slots) : null;
30 } 34 }
31 - const { hasPermission } = usePermission();  
32 - return hasPermission(value) ? getSlot(slots) : null;  
33 - }  
34 35
35 - /**  
36 - * 渲染编码按钮  
37 - * 这里只判断是否包含,具体实现可以根据项目自行写逻辑  
38 - */  
39 - function renderCodeAuth() {  
40 - const { value } = props;  
41 - if (!value) {  
42 - return getSlot(slots); 36 + /**
  37 + * 渲染编码按钮
  38 + * 这里只判断是否包含,具体实现可以根据项目自行写逻辑
  39 + */
  40 + function renderCodeAuth() {
  41 + const { value } = props;
  42 + if (!value) {
  43 + return getSlot(slots);
  44 + }
  45 + const { hasPermission } = usePermission();
  46 + return hasPermission(value) ? getSlot(slots) : null;
43 } 47 }
44 - const { hasPermission } = usePermission();  
45 - return hasPermission(value) ? getSlot(slots) : null;  
46 - }  
47 48
48 - return () => {  
49 - const mode = unref(getModeRef);  
50 - // 基于角色渲染  
51 - if (mode === PermissionModeEnum.ROLE) {  
52 - return renderRoleAuth();  
53 - }  
54 - // 基于后台编码渲染  
55 - if (mode === PermissionModeEnum.BACK) {  
56 - return renderCodeAuth();  
57 - }  
58 - return getSlot(slots);  
59 - };  
60 - },  
61 -}); 49 + return () => {
  50 + const mode = unref(getModeRef);
  51 + // 基于角色渲染
  52 + if (mode === PermissionModeEnum.ROLE) {
  53 + return renderRoleAuth();
  54 + }
  55 +
  56 + // 基于后台编码渲染
  57 + if (mode === PermissionModeEnum.BACK) {
  58 + return renderCodeAuth();
  59 + }
  60 +
  61 + return getSlot(slots);
  62 + };
  63 + },
  64 + });
  65 +</script>
src/components/Basic/index.ts
1 export { default as BasicArrow } from './src/BasicArrow.vue'; 1 export { default as BasicArrow } from './src/BasicArrow.vue';
2 -export { default as BasicHelp } from './src/BasicHelp'; 2 +export { default as BasicHelp } from './src/BasicHelp.vue';
3 export { default as BasicTitle } from './src/BasicTitle.vue'; 3 export { default as BasicTitle } from './src/BasicTitle.vue';
src/components/Basic/src/BasicHelp.less deleted 100644 → 0
1 -@import (reference) '../../../design/index.less';  
2 -  
3 -.base-help {  
4 - display: inline-block;  
5 - margin-left: 6px;  
6 - font-size: 14px;  
7 - color: @text-color-help-dark;  
8 - cursor: pointer;  
9 -  
10 - &:hover {  
11 - color: @primary-color;  
12 - }  
13 -  
14 - &__wrap {  
15 - p {  
16 - margin-bottom: 0;  
17 - }  
18 - }  
19 -}  
src/components/Basic/src/BasicHelp.tsx renamed to src/components/Basic/src/BasicHelp.vue
1 -import type { PropType } from 'vue'; 1 +<script lang="ts">
  2 + import type { PropType } from 'vue';
2 3
3 -import { Tooltip } from 'ant-design-vue';  
4 -import { InfoCircleOutlined } from '@ant-design/icons-vue';  
5 -import { defineComponent, computed, unref } from 'vue'; 4 + import { Tooltip } from 'ant-design-vue';
  5 + import { InfoCircleOutlined } from '@ant-design/icons-vue';
  6 + import { defineComponent, computed, unref, h } from 'vue';
6 7
7 -import { getPopupContainer } from '/@/utils'; 8 + import { getPopupContainer } from '/@/utils';
8 9
9 -import { isString, isArray } from '/@/utils/is';  
10 -import { getSlot } from '/@/utils/helper/tsxHelper';  
11 -import './BasicHelp.less';  
12 -export default defineComponent({  
13 - name: 'BaseHelp',  
14 - props: {  
15 - // max-width  
16 - maxWidth: {  
17 - type: String as PropType<string>,  
18 - default: '600px', 10 + import { isString, isArray } from '/@/utils/is';
  11 + import { getSlot } from '/@/utils/helper/tsxHelper';
  12 + export default defineComponent({
  13 + name: 'BaseHelp',
  14 + components: { Tooltip },
  15 + props: {
  16 + // max-width
  17 + maxWidth: {
  18 + type: String as PropType<string>,
  19 + default: '600px',
  20 + },
  21 + // Whether to display the serial number
  22 + showIndex: {
  23 + type: Boolean as PropType<boolean>,
  24 + default: false,
  25 + },
  26 + // Text list
  27 + text: {
  28 + type: [Array, String] as PropType<string[] | string>,
  29 + },
  30 + // color
  31 + color: {
  32 + type: String as PropType<string>,
  33 + default: '#ffffff',
  34 + },
  35 + fontSize: {
  36 + type: String as PropType<string>,
  37 + default: '14px',
  38 + },
  39 + absolute: {
  40 + type: Boolean as PropType<boolean>,
  41 + default: false,
  42 + },
  43 + // 定位
  44 + position: {
  45 + type: [Object] as PropType<any>,
  46 + default: () => ({
  47 + position: 'absolute',
  48 + left: 0,
  49 + bottom: 0,
  50 + }),
  51 + },
19 }, 52 },
20 - // Whether to display the serial number  
21 - showIndex: {  
22 - type: Boolean as PropType<boolean>,  
23 - default: false,  
24 - },  
25 - // Text list  
26 - text: {  
27 - type: [Array, String] as PropType<string[] | string>,  
28 - },  
29 - // color  
30 - color: {  
31 - type: String as PropType<string>,  
32 - default: '#ffffff',  
33 - },  
34 - fontSize: {  
35 - type: String as PropType<string>,  
36 - default: '14px',  
37 - },  
38 - absolute: {  
39 - type: Boolean as PropType<boolean>,  
40 - default: false,  
41 - },  
42 - // 定位  
43 - position: {  
44 - type: [Object] as PropType<any>,  
45 - default: () => ({  
46 - position: 'absolute',  
47 - left: 0,  
48 - bottom: 0,  
49 - }),  
50 - },  
51 - },  
52 - setup(props, { slots }) {  
53 - const getOverlayStyleRef = computed(() => {  
54 - return {  
55 - maxWidth: props.maxWidth, 53 + setup(props, { slots }) {
  54 + const getOverlayStyleRef = computed(() => {
  55 + return {
  56 + maxWidth: props.maxWidth,
  57 + };
  58 + });
  59 + const getWrapStyleRef = computed(() => {
  60 + return {
  61 + color: props.color,
  62 + fontSize: props.fontSize,
  63 + };
  64 + });
  65 + const getMainStyleRef = computed(() => {
  66 + return props.absolute ? props.position : {};
  67 + });
  68 +
  69 + /**
  70 + * @description: 渲染内容
  71 + */
  72 + const renderTitle = () => {
  73 + const list = props.text;
  74 + if (isString(list)) {
  75 + return h('p', list);
  76 + }
  77 + if (isArray(list)) {
  78 + return list.map((item, index) => {
  79 + return h('p', { key: item }, [props.showIndex ? `${index + 1}. ` : '', item]);
  80 + });
  81 + }
  82 + return null;
56 }; 83 };
57 - });  
58 - const getWrapStyleRef = computed(() => {  
59 - return {  
60 - color: props.color,  
61 - fontSize: props.fontSize, 84 + return () => {
  85 + return h(
  86 + Tooltip,
  87 + {
  88 + title: h(
  89 + 'div',
  90 + {
  91 + style: unref(getWrapStyleRef),
  92 + },
  93 + [renderTitle()]
  94 + ) as any,
  95 + overlayClassName: 'base-help__wrap',
  96 + autoAdjustOverflow: true,
  97 + overlayStyle: unref(getOverlayStyleRef),
  98 + placement: 'right',
  99 + getPopupContainer: () => getPopupContainer(),
  100 + },
  101 + {
  102 + default: () =>
  103 + h(
  104 + 'span',
  105 + {
  106 + class: 'base-help',
  107 + style: unref(getMainStyleRef),
  108 + },
  109 + getSlot(slots) || h(InfoCircleOutlined)
  110 + ),
  111 + }
  112 + );
62 }; 113 };
63 - });  
64 - const getMainStyleRef = computed(() => {  
65 - return props.absolute ? props.position : {};  
66 - }); 114 + },
  115 + });
  116 +</script>
  117 +<style lang="less">
  118 + @import (reference) '../../../design/index.less';
67 119
68 - /**  
69 - * @description: 渲染内容  
70 - */  
71 - const renderTitle = () => {  
72 - const list = props.text;  
73 - if (isString(list)) {  
74 - return <p>{list}</p>;  
75 - }  
76 - if (isArray(list)) {  
77 - return list.map((item, index) => {  
78 - return (  
79 - <p key={item}>  
80 - {props.showIndex ? `${index + 1}. ` : ''}  
81 - {item}  
82 - </p>  
83 - );  
84 - }); 120 + .base-help {
  121 + display: inline-block;
  122 + margin-left: 6px;
  123 + font-size: 14px;
  124 + color: @text-color-help-dark;
  125 + cursor: pointer;
  126 +
  127 + &:hover {
  128 + color: @primary-color;
  129 + }
  130 +
  131 + &__wrap {
  132 + p {
  133 + margin-bottom: 0;
85 } 134 }
86 - return null;  
87 - };  
88 - return () => (  
89 - <Tooltip  
90 - title={(<div style={unref(getWrapStyleRef)}>{renderTitle()}</div>) as any}  
91 - placement="right"  
92 - overlayStyle={unref(getOverlayStyleRef)}  
93 - autoAdjustOverflow={true}  
94 - overlayClassName="base-help__wrap"  
95 - getPopupContainer={() => getPopupContainer()}  
96 - >  
97 - {{  
98 - default: () => (  
99 - <span class="base-help" style={unref(getMainStyleRef)}>  
100 - {getSlot(slots) || <InfoCircleOutlined />}  
101 - </span>  
102 - ),  
103 - }}  
104 - </Tooltip>  
105 - );  
106 - },  
107 -}); 135 + }
  136 + }
  137 +</style>
src/components/Button/types.ts deleted 100644 → 0
1 -import { VNodeChild } from 'vue';  
2 -  
3 -export interface BasicButtonProps {  
4 - /**  
5 - * can be set to primary ghost dashed danger(added in 2.7) or omitted (meaning default)  
6 - * @default 'default'  
7 - * @type string  
8 - */  
9 - type?: 'primary' | 'danger' | 'dashed' | 'ghost' | 'default';  
10 -  
11 - /**  
12 - * set the original html type of button  
13 - * @default 'button'  
14 - * @type string  
15 - */  
16 - htmlType?: 'button' | 'submit' | 'reset' | 'menu';  
17 -  
18 - /**  
19 - * set the icon of button  
20 - * @type string  
21 - */  
22 - icon?: VNodeChild | JSX.Element;  
23 -  
24 - /**  
25 - * can be set to circle or circle-outline or omitted  
26 - * @type string  
27 - */  
28 - shape?: 'circle' | 'circle-outline';  
29 -  
30 - /**  
31 - * can be set to small large or omitted  
32 - * @default 'default'  
33 - * @type string  
34 - */  
35 - size?: 'small' | 'large' | 'default';  
36 -  
37 - /**  
38 - * set the loading status of button  
39 - * @default false  
40 - * @type boolean | { delay: number }  
41 - */  
42 - loading?: boolean | { delay: number };  
43 -  
44 - /**  
45 - * disabled state of button  
46 - * @default false  
47 - * @type boolean  
48 - */  
49 - disabled?: boolean;  
50 -  
51 - /**  
52 - * make background transparent and invert text and border colors, added in 2.7  
53 - * @default false  
54 - * @type boolean  
55 - */  
56 - ghost?: boolean;  
57 -  
58 - /**  
59 - * option to fit button width to its parent width  
60 - * @default false  
61 - * @type boolean  
62 - */  
63 - block?: boolean;  
64 -  
65 - onClick?: (e?: Event) => void;  
66 -}  
src/components/Table/src/components/TableAction.tsx
@@ -84,10 +84,11 @@ export default defineComponent({ @@ -84,10 +84,11 @@ export default defineComponent({
84 const { dropDownActions = [], actions } = props; 84 const { dropDownActions = [], actions } = props;
85 return ( 85 return (
86 <div class={prefixCls}> 86 <div class={prefixCls}>
87 - {actions?.map((action, index) => {  
88 - return renderPopConfirm(action, index);  
89 - })}  
90 - {dropDownActions?.length && ( 87 + {actions &&
  88 + actions.map((action, index) => {
  89 + return renderPopConfirm(action, index);
  90 + })}
  91 + {dropDownActions && dropDownActions.length && (
91 <Dropdown> 92 <Dropdown>
92 {{ 93 {{
93 default: dropdownDefaultSLot, 94 default: dropdownDefaultSLot,
src/components/Table/src/components/renderEditableCell.tsx
@@ -45,8 +45,8 @@ const EditableCell = defineComponent({ @@ -45,8 +45,8 @@ const EditableCell = defineComponent({
45 const isEditRef = ref(false); 45 const isEditRef = ref(false);
46 const currentValueRef = ref<string | boolean>(props.value); 46 const currentValueRef = ref<string | boolean>(props.value);
47 47
48 - function handleChange(e: ChangeEvent | string | boolean) {  
49 - if (Reflect.has((e as ChangeEvent)?.target, 'value')) { 48 + function handleChange(e: any) {
  49 + if (e && e.target && Reflect.has(e.target, 'value')) {
50 currentValueRef.value = (e as ChangeEvent).target.value; 50 currentValueRef.value = (e as ChangeEvent).target.value;
51 } 51 }
52 if (isString(e) || isBoolean(e)) { 52 if (isString(e) || isBoolean(e)) {
@@ -58,7 +58,7 @@ const EditableCell = defineComponent({ @@ -58,7 +58,7 @@ const EditableCell = defineComponent({
58 isEditRef.value = true; 58 isEditRef.value = true;
59 nextTick(() => { 59 nextTick(() => {
60 const el = unref(elRef); 60 const el = unref(elRef);
61 - el?.focus(); 61 + el && el.focus();
62 }); 62 });
63 } 63 }
64 64
@@ -84,7 +84,7 @@ const EditableCell = defineComponent({ @@ -84,7 +84,7 @@ const EditableCell = defineComponent({
84 function onClickOutside() { 84 function onClickOutside() {
85 const { component } = props; 85 const { component } = props;
86 86
87 - if (component?.includes('Input')) { 87 + if (component && component.includes('Input')) {
88 handleCancel(); 88 handleCancel();
89 } 89 }
90 } 90 }
src/components/Table/src/hooks/useDataSource.ts
@@ -89,7 +89,7 @@ export function useDataSource( @@ -89,7 +89,7 @@ export function useDataSource(
89 pageParams = {}; 89 pageParams = {};
90 } else { 90 } else {
91 const { current, pageSize } = unref(getPaginationRef) as PaginationProps; 91 const { current, pageSize } = unref(getPaginationRef) as PaginationProps;
92 - pageParams[pageField] = opt?.page || current; 92 + pageParams[pageField] = (opt && opt.page) || current;
93 pageParams[sizeField] = pageSize; 93 pageParams[sizeField] = pageSize;
94 } 94 }
95 95
src/components/Tinymce/src/Editor.vue
@@ -53,13 +53,12 @@ @@ -53,13 +53,12 @@
53 }); 53 });
54 54
55 const initOptions = computed(() => { 55 const initOptions = computed(() => {
56 - const { height, menubar } = props; 56 + const { height, options } = props;
57 return { 57 return {
58 selector: `#${unref(tinymceId)}`, 58 selector: `#${unref(tinymceId)}`,
59 height: height, 59 height: height,
60 toolbar: toolbar, 60 toolbar: toolbar,
61 - theme: 'silver',  
62 - menubar: menubar, 61 + menubar: 'file edit insert view format table',
63 plugins: plugins, 62 plugins: plugins,
64 // 语言包 63 // 语言包
65 language_url: 'resource/tinymce/langs/zh_CN.js', 64 language_url: 'resource/tinymce/langs/zh_CN.js',
@@ -70,6 +69,7 @@ @@ -70,6 +69,7 @@
70 advlist_bullet_styles: 'square', 69 advlist_bullet_styles: 'square',
71 advlist_number_styles: 'default', 70 advlist_number_styles: 'default',
72 object_resizing: false, 71 object_resizing: false,
  72 + ...options,
73 setup: (editor: any) => { 73 setup: (editor: any) => {
74 editorRef.value = editor; 74 editorRef.value = editor;
75 editor.on('init', (e: Event) => initSetup(e)); 75 editor.on('init', (e: Event) => initSetup(e));
src/components/Tinymce/src/props.ts
1 import { PropType } from 'vue'; 1 import { PropType } from 'vue';
2 2
3 export const basicProps = { 3 export const basicProps = {
4 - menubar: {  
5 - type: String as PropType<string>,  
6 - default: 'file edit insert view format table', 4 + options: {
  5 + type: Object as PropType<any>,
  6 + default: {},
7 }, 7 },
8 value: { 8 value: {
9 type: String as PropType<string>, 9 type: String as PropType<string>,
src/views/demo/editor/tinymce/index.vue
1 <template> 1 <template>
2 - <div class="flex p-4">  
3 - {{ value }} 2 + <div class="p-4">
4 <Tinymce v-model="value" @change="handleChange" width="100%" /> 3 <Tinymce v-model="value" @change="handleChange" width="100%" />
5 </div> 4 </div>
6 </template> 5 </template>
@@ -15,9 +14,6 @@ @@ -15,9 +14,6 @@
15 function handleChange(value: string) { 14 function handleChange(value: string) {
16 console.log(value); 15 console.log(value);
17 } 16 }
18 - // setTimeout(() => {  
19 - // value.value = '1233';  
20 - // }, 5000);  
21 return { handleChange, value }; 17 return { handleChange, value };
22 }, 18 },
23 }); 19 });
vite.config.ts
@@ -8,7 +8,6 @@ import { @@ -8,7 +8,6 @@ import {
8 // externals, 8 // externals,
9 cdnConf, 9 cdnConf,
10 } from './build/config/vite/cdn'; 10 } from './build/config/vite/cdn';
11 -  
12 import { createProxy } from './build/config/vite/proxy'; 11 import { createProxy } from './build/config/vite/proxy';
13 import { createMockServer } from 'vite-plugin-mock'; 12 import { createMockServer } from 'vite-plugin-mock';
14 import PurgeIcons from 'vite-plugin-purge-icons'; 13 import PurgeIcons from 'vite-plugin-purge-icons';