Commit 2e11ea677b0bb8fc1a5d8d3bc5a9a664195adb7a
1 parent
39d629a0
wip: add cropper iamge component
Showing
15 changed files
with
222 additions
and
43 deletions
package.json
... | ... | @@ -37,6 +37,7 @@ |
37 | 37 | "ant-design-vue": "^2.1.2", |
38 | 38 | "apexcharts": "^3.26.0", |
39 | 39 | "axios": "^0.21.1", |
40 | + "cropperjs": "^1.5.11", | |
40 | 41 | "crypto-js": "^4.0.0", |
41 | 42 | "echarts": "^5.0.2", |
42 | 43 | "lodash-es": "^4.17.21", |
... | ... | @@ -91,7 +92,7 @@ |
91 | 92 | "esno": "^0.5.0", |
92 | 93 | "fs-extra": "^9.1.0", |
93 | 94 | "http-server": "^0.12.3", |
94 | - "husky": "^5.2.0", | |
95 | + "husky": "^6.0.0", | |
95 | 96 | "inquirer": "^8.0.0", |
96 | 97 | "is-ci": "^3.0.0", |
97 | 98 | "less": "^4.1.1", |
... | ... | @@ -117,7 +118,7 @@ |
117 | 118 | "vite-plugin-style-import": "^0.9.1", |
118 | 119 | "vite-plugin-svg-icons": "^0.4.0", |
119 | 120 | "vite-plugin-theme": "^0.5.0", |
120 | - "vite-plugin-windicss": "0.10.4", | |
121 | + "vite-plugin-windicss": "0.11.0", | |
121 | 122 | "vue-eslint-parser": "^7.6.0" |
122 | 123 | }, |
123 | 124 | "resolutions": { | ... | ... |
src/components/Cropper/index.ts
0 → 100644
src/components/Cropper/src/AvatarCropper.vue
0 → 100644
1 | +<template> | |
2 | + <div :class="$attrs.class" :style="$attrs.style"> </div> | |
3 | +</template> | |
4 | +<script lang="ts"> | |
5 | + // TODO | |
6 | + import { defineComponent } from 'vue'; | |
7 | + | |
8 | + export default defineComponent({ | |
9 | + name: 'AvatarCropper', | |
10 | + props: {}, | |
11 | + setup() { | |
12 | + return {}; | |
13 | + }, | |
14 | + }); | |
15 | +</script> | ... | ... |
src/components/Cropper/src/index.vue
0 → 100644
1 | +<template> | |
2 | + <div :class="$attrs.class" :style="$attrs.style"> | |
3 | + <img ref="imgElRef" :src="src" :alt="alt" :crossorigin="crossorigin" :style="getImageStyle" /> | |
4 | + </div> | |
5 | +</template> | |
6 | +<script lang="ts"> | |
7 | + import type { CSSProperties } from 'vue'; | |
8 | + | |
9 | + import { defineComponent, onMounted, ref, unref, computed } from 'vue'; | |
10 | + | |
11 | + import Cropper from 'cropperjs'; | |
12 | + import 'cropperjs/dist/cropper.css'; | |
13 | + | |
14 | + type Options = Cropper.Options; | |
15 | + | |
16 | + const defaultOptions: Cropper.Options = { | |
17 | + aspectRatio: 16 / 9, | |
18 | + zoomable: true, | |
19 | + zoomOnTouch: true, | |
20 | + zoomOnWheel: true, | |
21 | + cropBoxMovable: true, | |
22 | + cropBoxResizable: true, | |
23 | + toggleDragModeOnDblclick: true, | |
24 | + autoCrop: true, | |
25 | + background: true, | |
26 | + highlight: true, | |
27 | + center: true, | |
28 | + responsive: true, | |
29 | + restore: true, | |
30 | + checkCrossOrigin: true, | |
31 | + checkOrientation: true, | |
32 | + scalable: true, | |
33 | + modal: true, | |
34 | + guides: true, | |
35 | + movable: true, | |
36 | + rotatable: true, | |
37 | + }; | |
38 | + export default defineComponent({ | |
39 | + name: 'CropperImage', | |
40 | + props: { | |
41 | + src: { | |
42 | + type: String, | |
43 | + required: true, | |
44 | + }, | |
45 | + alt: { | |
46 | + type: String, | |
47 | + }, | |
48 | + height: { | |
49 | + type: String, | |
50 | + default: '500px', | |
51 | + }, | |
52 | + crossorigin: { | |
53 | + type: String, | |
54 | + default: undefined, | |
55 | + }, | |
56 | + imageStyle: { | |
57 | + type: Object as PropType<CSSProperties>, | |
58 | + default: {}, | |
59 | + }, | |
60 | + options: { | |
61 | + type: Object as PropType<Options>, | |
62 | + default: {}, | |
63 | + }, | |
64 | + }, | |
65 | + setup(props) { | |
66 | + const imgElRef = ref<ElRef<HTMLImageElement>>(null); | |
67 | + const cropper = ref<Nullable<Cropper>>(null); | |
68 | + | |
69 | + const isReady = ref(false); | |
70 | + | |
71 | + const getImageStyle = computed( | |
72 | + (): CSSProperties => { | |
73 | + return { | |
74 | + height: props.height, | |
75 | + maxWidth: '100%', | |
76 | + ...props.imageStyle, | |
77 | + }; | |
78 | + } | |
79 | + ); | |
80 | + | |
81 | + async function init() { | |
82 | + const imgEl = unref(imgElRef); | |
83 | + if (!imgEl) { | |
84 | + return; | |
85 | + } | |
86 | + cropper.value = new Cropper(imgEl, { | |
87 | + ...defaultOptions, | |
88 | + ready: () => { | |
89 | + isReady.value = true; | |
90 | + }, | |
91 | + ...props.options, | |
92 | + }); | |
93 | + } | |
94 | + | |
95 | + onMounted(init); | |
96 | + | |
97 | + return { imgElRef, getImageStyle, isReady }; | |
98 | + }, | |
99 | + }); | |
100 | +</script> | ... | ... |
src/components/Dropdown/src/Dropdown.vue
... | ... | @@ -5,14 +5,20 @@ |
5 | 5 | </span> |
6 | 6 | <template #overlay> |
7 | 7 | <a-menu :selectedKeys="selectedKeys"> |
8 | - <template v-for="item in getMenuList" :key="`${item.event}`"> | |
8 | + <template v-for="item in dropMenuList" :key="`${item.event}`"> | |
9 | 9 | <a-menu-item |
10 | 10 | v-bind="getAttr(item.event)" |
11 | 11 | @click="handleClickMenu(item)" |
12 | 12 | :disabled="item.disabled" |
13 | 13 | > |
14 | - <Icon :icon="item.icon" v-if="item.icon" /> | |
15 | - <span class="ml-1">{{ item.text }}</span> | |
14 | + <Popconfirm v-if="popconfirm" v-bind="item"> | |
15 | + <Icon :icon="item.icon" v-if="item.icon" /> | |
16 | + <span class="ml-1">{{ item.text }}</span> | |
17 | + </Popconfirm> | |
18 | + <template v-else> | |
19 | + <Icon :icon="item.icon" v-if="item.icon" /> | |
20 | + <span class="ml-1">{{ item.text }}</span> | |
21 | + </template> | |
16 | 22 | </a-menu-item> |
17 | 23 | <a-menu-divider v-if="item.divider" :key="`d-${item.event}`" /> |
18 | 24 | </template> |
... | ... | @@ -25,9 +31,9 @@ |
25 | 31 | import type { PropType } from 'vue'; |
26 | 32 | import type { DropMenu } from './types'; |
27 | 33 | |
28 | - import { defineComponent, computed, unref } from 'vue'; | |
29 | - import { Dropdown, Menu } from 'ant-design-vue'; | |
30 | - import Icon from '/@/components/Icon/index'; | |
34 | + import { defineComponent } from 'vue'; | |
35 | + import { Dropdown, Menu, Popconfirm } from 'ant-design-vue'; | |
36 | + import { Icon } from '/@/components/Icon'; | |
31 | 37 | |
32 | 38 | export default defineComponent({ |
33 | 39 | name: 'BasicDropdown', |
... | ... | @@ -37,8 +43,10 @@ |
37 | 43 | [Menu.Item.name]: Menu.Item, |
38 | 44 | [Menu.Divider.name]: Menu.Divider, |
39 | 45 | Icon, |
46 | + Popconfirm, | |
40 | 47 | }, |
41 | 48 | props: { |
49 | + popconfirm: Boolean, | |
42 | 50 | /** |
43 | 51 | * the trigger mode which executes the drop-down action |
44 | 52 | * @default ['hover'] |
... | ... | @@ -61,19 +69,15 @@ |
61 | 69 | }, |
62 | 70 | emits: ['menuEvent'], |
63 | 71 | setup(props, { emit }) { |
64 | - const getMenuList = computed(() => props.dropMenuList); | |
65 | - | |
66 | 72 | function handleClickMenu(item: DropMenu) { |
67 | 73 | const { event } = item; |
68 | - const menu = unref(getMenuList).find((item) => `${item.event}` === `${event}`); | |
74 | + const menu = props.dropMenuList.find((item) => `${item.event}` === `${event}`); | |
69 | 75 | emit('menuEvent', menu); |
70 | 76 | item.onClick?.(); |
71 | 77 | } |
72 | - | |
73 | 78 | return { |
74 | 79 | handleClickMenu, |
75 | - getMenuList, | |
76 | - getAttr: (key: string) => ({ key }), | |
80 | + getAttr: (key: string | number) => ({ key }), | |
77 | 81 | }; |
78 | 82 | }, |
79 | 83 | }); | ... | ... |
src/components/Table/src/components/TableAction.vue
... | ... | @@ -10,7 +10,12 @@ |
10 | 10 | v-if="divider && index < getActions.length - (dropDownActions ? 0 : 1)" |
11 | 11 | /> |
12 | 12 | </template> |
13 | - <Dropdown :trigger="['hover']" :dropMenuList="getDropList" v-if="dropDownActions"> | |
13 | + <Dropdown | |
14 | + :trigger="['hover']" | |
15 | + :dropMenuList="getDropdownList" | |
16 | + popconfirm | |
17 | + v-if="dropDownActions" | |
18 | + > | |
14 | 19 | <slot name="more"></slot> |
15 | 20 | <a-button type="link" size="small" v-if="!$slots.more"> |
16 | 21 | <MoreOutlined class="icon-more" /> |
... | ... | @@ -71,11 +76,12 @@ |
71 | 76 | }); |
72 | 77 | }); |
73 | 78 | |
74 | - const getDropList = computed(() => { | |
79 | + const getDropdownList = computed(() => { | |
75 | 80 | return (toRaw(props.dropDownActions) || []).map((action, index) => { |
76 | - const { label } = action; | |
81 | + const { label, popConfirm } = action; | |
77 | 82 | return { |
78 | 83 | ...action, |
84 | + ...popConfirm, | |
79 | 85 | text: label, |
80 | 86 | divider: index < props.dropDownActions.length - 1 ? props.divider : false, |
81 | 87 | }; |
... | ... | @@ -88,7 +94,7 @@ |
88 | 94 | return actionColumn?.align ?? 'left'; |
89 | 95 | }); |
90 | 96 | |
91 | - return { prefixCls, getActions, getDropList, getAlign }; | |
97 | + return { prefixCls, getActions, getDropdownList, getAlign }; | |
92 | 98 | }, |
93 | 99 | }); |
94 | 100 | </script> | ... | ... |
src/locales/lang/en/routes/demo/comp.ts
src/locales/lang/zh_CN/routes/demo/comp.ts
src/router/menus/modules/demo/comp.ts
... | ... | @@ -6,7 +6,9 @@ const menu: MenuModule = { |
6 | 6 | menu: { |
7 | 7 | name: t('routes.demo.comp.comp'), |
8 | 8 | path: '/comp', |
9 | - | |
9 | + tag: { | |
10 | + dot: true, | |
11 | + }, | |
10 | 12 | children: [ |
11 | 13 | { |
12 | 14 | path: 'basic', |
... | ... | @@ -115,6 +117,13 @@ const menu: MenuModule = { |
115 | 117 | ], |
116 | 118 | }, |
117 | 119 | { |
120 | + path: 'cropper', | |
121 | + name: t('routes.demo.comp.cropperImage'), | |
122 | + tag: { | |
123 | + content: 'new', | |
124 | + }, | |
125 | + }, | |
126 | + { | |
118 | 127 | path: 'countTo', |
119 | 128 | name: t('routes.demo.comp.countTo'), |
120 | 129 | }, | ... | ... |
src/router/routes/modules/demo/comp.ts
... | ... | @@ -233,6 +233,14 @@ const comp: AppRouteModule = { |
233 | 233 | }, |
234 | 234 | }, |
235 | 235 | { |
236 | + path: 'cropper', | |
237 | + name: 'CropperDemo', | |
238 | + component: () => import('/@/views/demo/comp/cropper/index.vue'), | |
239 | + meta: { | |
240 | + title: t('routes.demo.comp.cropperImage'), | |
241 | + }, | |
242 | + }, | |
243 | + { | |
236 | 244 | path: 'timestamp', |
237 | 245 | name: 'TimeDemo', |
238 | 246 | component: () => import('/@/views/demo/comp/time/index.vue'), | ... | ... |
src/views/demo/comp/cropper/index.vue
0 → 100644
1 | +<template> | |
2 | + <PageWrapper title="图片裁剪示例" contentBackground> | |
3 | + <CropperImage src="https://fengyuanchen.github.io/cropperjs/images/picture.jpg"></CropperImage> | |
4 | + </PageWrapper> | |
5 | +</template> | |
6 | +<script lang="ts"> | |
7 | + import { defineComponent } from 'vue'; | |
8 | + import { PageWrapper } from '/@/components/Page'; | |
9 | + | |
10 | + import { CropperImage } from '/@/components/Cropper'; | |
11 | + | |
12 | + import img from '/@/assets/images/header.jpg'; | |
13 | + export default defineComponent({ | |
14 | + components: { | |
15 | + PageWrapper, | |
16 | + CropperImage, | |
17 | + }, | |
18 | + setup() { | |
19 | + return { img }; | |
20 | + }, | |
21 | + }); | |
22 | +</script> | ... | ... |
src/views/demo/page/account/setting/BaseSetting.vue
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | <div class="mb-2"> 头像 </div> |
10 | 10 | <img width="140" :src="headerImg" /> |
11 | 11 | <Upload :showUploadList="false"> |
12 | - <Button type="ghost" class="ml-5"> <Icon icon="feather:upload" />更换头像 </Button> | |
12 | + <Button class="ml-5"> <Icon icon="feather:upload" />更换头像 </Button> | |
13 | 13 | </Upload> |
14 | 14 | </div> |
15 | 15 | </a-col> | ... | ... |
src/views/demo/table/FixedColumn.vue
vite.config.ts
yarn.lock
... | ... | @@ -2077,10 +2077,10 @@ |
2077 | 2077 | dependencies: |
2078 | 2078 | vue-demi latest |
2079 | 2079 | |
2080 | -"@windicss/plugin-utils@0.10.4": | |
2081 | - version "0.10.4" | |
2082 | - resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-0.10.4.tgz#ed9163b09e030f7358cc4742b1f2b6c92d084d5d" | |
2083 | - integrity sha512-jQu69qzA56Lv18OK8U4mUTDV17st4EdPawQuaRG2VNK+ZEQWYsMNnqGxhzDTl/NhWTGCcTb3D6mlFPNo0QDOFg== | |
2080 | +"@windicss/plugin-utils@0.11.0": | |
2081 | + version "0.11.0" | |
2082 | + resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-0.11.0.tgz#142fe810c9cf71719074518295f65bd01f0ac895" | |
2083 | + integrity sha512-NIBJ7/wG8Ty///Qxktefud4OI18XjZkycW6DSkWV7++aYyZOdDgGRn493pU+5QZuXeXU8iNR6NKZDtFNcYD7kQ== | |
2084 | 2084 | dependencies: |
2085 | 2085 | debug "^4.3.2" |
2086 | 2086 | fast-glob "^3.2.5" |
... | ... | @@ -2088,7 +2088,7 @@ |
2088 | 2088 | micromatch "^4.0.2" |
2089 | 2089 | pirates "^4.0.1" |
2090 | 2090 | sucrase "^3.17.1" |
2091 | - windicss "^2.5.7" | |
2091 | + windicss "^2.5.8" | |
2092 | 2092 | |
2093 | 2093 | "@zxcvbn-ts/core@^0.3.0": |
2094 | 2094 | version "0.3.0" |
... | ... | @@ -3582,6 +3582,11 @@ create-require@^1.1.0: |
3582 | 3582 | resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" |
3583 | 3583 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== |
3584 | 3584 | |
3585 | +cropperjs@^1.5.11: | |
3586 | + version "1.5.11" | |
3587 | + resolved "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.11.tgz#502ae6d8ca098b124de6813601cca70015879fc0" | |
3588 | + integrity sha512-SJUeBBhtNBnnn+UrLKluhFRIXLJn7XFPv8QN1j49X5t+BIMwkgvDev541f96bmu8Xe0TgCx3gON22KmY/VddaA== | |
3589 | + | |
3585 | 3590 | cross-env@^7.0.3: |
3586 | 3591 | version "7.0.3" |
3587 | 3592 | resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" |
... | ... | @@ -5698,10 +5703,10 @@ husky@^5.1.3: |
5698 | 5703 | resolved "https://registry.npmjs.org/husky/-/husky-5.1.3.tgz#1a0645a4fe3ffc006c4d0d8bd0bcb4c98787cc9d" |
5699 | 5704 | integrity sha512-fbNJ+Gz5wx2LIBtMweJNY1D7Uc8p1XERi5KNRMccwfQA+rXlxWNSdUxswo0gT8XqxywTIw7Ywm/F4v/O35RdMg== |
5700 | 5705 | |
5701 | -husky@^5.2.0: | |
5702 | - version "5.2.0" | |
5703 | - resolved "https://registry.npmjs.org/husky/-/husky-5.2.0.tgz#fc5e1c2300d34855d47de4753607d00943fc0802" | |
5704 | - integrity sha512-AM8T/auHXRBxlrfPVLKP6jt49GCM2Zz47m8G3FOMsLmTv8Dj/fKVWE0Rh2d4Qrvmy131xEsdQnb3OXRib67PGg== | |
5706 | +husky@^6.0.0: | |
5707 | + version "6.0.0" | |
5708 | + resolved "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz#810f11869adf51604c32ea577edbc377d7f9319e" | |
5709 | + integrity sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ== | |
5705 | 5710 | |
5706 | 5711 | iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: |
5707 | 5712 | version "0.4.24" |
... | ... | @@ -11005,15 +11010,15 @@ vite-plugin-theme@^0.5.0: |
11005 | 11010 | tinycolor2 "^1.4.2" |
11006 | 11011 | ts-jest "^26.5.3" |
11007 | 11012 | |
11008 | -vite-plugin-windicss@0.10.4: | |
11009 | - version "0.10.4" | |
11010 | - resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.10.4.tgz#e93577111ea0a55befbe4e2aa2e596f55f6b74b2" | |
11011 | - integrity sha512-P7alH2dGGw3OTgjs9yZG2w0i+o1HKD8PChwhm2ftP+lLCe1xDL3LReheuRil9p2xPYzrVouER2YTbIdLUEThrQ== | |
11013 | +vite-plugin-windicss@0.11.0: | |
11014 | + version "0.11.0" | |
11015 | + resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.11.0.tgz#784b3b7c72d29e85d52dad705a846f8e2366a2fc" | |
11016 | + integrity sha512-DSXomaGHXAXIF9zPk7T9KG8m1bMNNiIHpeoClX44qxNHT7ryI6iDI8gkWdNfYVjxjcoXSTxKqKa11MA+C7mmAA== | |
11012 | 11017 | dependencies: |
11013 | - "@windicss/plugin-utils" "0.10.4" | |
11018 | + "@windicss/plugin-utils" "0.11.0" | |
11014 | 11019 | chalk "^4.1.0" |
11015 | 11020 | debug "^4.3.2" |
11016 | - windicss "^2.5.7" | |
11021 | + windicss "^2.5.8" | |
11017 | 11022 | |
11018 | 11023 | vite@2.1.3: |
11019 | 11024 | version "2.1.3" |
... | ... | @@ -11187,10 +11192,10 @@ which@^2.0.1, which@^2.0.2: |
11187 | 11192 | dependencies: |
11188 | 11193 | isexe "^2.0.0" |
11189 | 11194 | |
11190 | -windicss@^2.5.7: | |
11191 | - version "2.5.7" | |
11192 | - resolved "https://registry.npmjs.org/windicss/-/windicss-2.5.7.tgz#aea36568cfb412e1c673468496e920f21ef06086" | |
11193 | - integrity sha512-gsWZkotmw9Hr7yZy2nJAp46pmgMO1wXFFa3rfLWm57KDM31U/AucksQnwZi7zxsKM9c6O/z/61/Uvv4J096zKA== | |
11195 | +windicss@^2.5.8: | |
11196 | + version "2.5.8" | |
11197 | + resolved "https://registry.npmjs.org/windicss/-/windicss-2.5.8.tgz#254980044de3031276062b90cfce53c13ee489bf" | |
11198 | + integrity sha512-zHkozdIqv1YTIGHBOHeFGsuZVTN5yAMz6FW5Bp8im9JZxSRZLOLKdJB0K75SL13iLHKXHrC1ukwJjjL8CohrUw== | |
11194 | 11199 | |
11195 | 11200 | wmf@~1.0.1: |
11196 | 11201 | version "1.0.2" | ... | ... |