gi-component 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/dist/index.es.js +2241 -0
- package/dist/dist/index.es.js.map +1 -0
- package/dist/dist/index.umd.js +2 -0
- package/dist/dist/index.umd.js.map +1 -0
- package/dist/gi.css +1 -0
- package/dist/index.d.ts +1 -0
- package/package.json +56 -0
- package/packages/components/button/index.ts +5 -0
- package/packages/components/button/src/button.vue +59 -0
- package/packages/components/button/src/type.ts +15 -0
- package/packages/components/card/index.ts +5 -0
- package/packages/components/card/src/card.vue +166 -0
- package/packages/components/card/src/type.ts +12 -0
- package/packages/components/dialog/index.ts +6 -0
- package/packages/components/dialog/src/dialog.ts +87 -0
- package/packages/components/dialog/src/dialog.vue +122 -0
- package/packages/components/dialog/src/type.ts +16 -0
- package/packages/components/edit-table/index.ts +5 -0
- package/packages/components/edit-table/src/edit-table.vue +207 -0
- package/packages/components/edit-table/src/type.ts +69 -0
- package/packages/components/form/index.ts +5 -0
- package/packages/components/form/src/form.vue +465 -0
- package/packages/components/form/src/type.ts +98 -0
- package/packages/components/grid/index.ts +8 -0
- package/packages/components/grid/src/context.ts +30 -0
- package/packages/components/grid/src/grid-item.vue +143 -0
- package/packages/components/grid/src/grid.vue +151 -0
- package/packages/components/grid/src/hook/use-index.ts +63 -0
- package/packages/components/grid/src/hook/use-responsive-state.ts +66 -0
- package/packages/components/grid/src/hook/use-responsive-value.ts +36 -0
- package/packages/components/grid/src/interface.ts +74 -0
- package/packages/components/grid/src/type.ts +0 -0
- package/packages/components/grid/src/utils/global-config.ts +6 -0
- package/packages/components/grid/src/utils/index.ts +73 -0
- package/packages/components/grid/src/utils/is.ts +9 -0
- package/packages/components/grid/src/utils/responsive-observe.ts +135 -0
- package/packages/components/input-group/index.ts +5 -0
- package/packages/components/input-group/src/input-group.vue +92 -0
- package/packages/components/input-group/src/type.ts +1 -0
- package/packages/components/input-search/index.ts +5 -0
- package/packages/components/input-search/src/input-search.vue +62 -0
- package/packages/components/input-search/src/type.ts +6 -0
- package/packages/components/page-layout/index.ts +5 -0
- package/packages/components/page-layout/src/page-layout.vue +180 -0
- package/packages/components/page-layout/src/split-button.vue +106 -0
- package/packages/components/page-layout/src/type.ts +12 -0
- package/packages/components/table/index.ts +5 -0
- package/packages/components/table/src/TableColumn.vue +49 -0
- package/packages/components/table/src/table.vue +85 -0
- package/packages/components/table/src/type.ts +22 -0
- package/packages/components/tabs/index.ts +5 -0
- package/packages/components/tabs/src/tabs.vue +148 -0
- package/packages/components/tabs/src/type.ts +15 -0
- package/packages/components.d.ts +26 -0
- package/packages/hooks/index.ts +1 -0
- package/packages/hooks/useBemClass.ts +11 -0
- package/packages/index.ts +78 -0
- package/packages/styles/index.scss +176 -0
- package/packages/styles/var.scss +1 -0
- package/packages/utils/createSelectDialog.ts +67 -0
- package/packages/utils/index.ts +1 -0
package/dist/gi.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.gi-card[data-v-c2f199fb]{background-color:var(--el-bg-color);display:flex;flex-direction:column;overflow:hidden;box-sizing:border-box;--card-padding-x: var(--padding-x);--card-padding-x-small: var(--padding-x-small);--card-padding-y: var(--padding-y);--card-padding-y-small: var(--padding-y-small)}.gi-card--bordered[data-v-c2f199fb]{border:1px solid var(--el-border-color)}.gi-card-header[data-v-c2f199fb]{height:46px;padding:0 var(--card-padding-x);display:flex;justify-content:space-between;align-items:center;color:var(--el-text-color-primary);box-sizing:border-box;position:relative;flex-shrink:0}.gi-card-header__title[data-v-c2f199fb]{position:relative;line-height:1.3em;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;box-sizing:border-box;font-weight:500;font-size:16px}.gi-card-header__extra[data-v-c2f199fb]{display:flex}.gi-card-header--bordered[data-v-c2f199fb]{border-bottom:1px solid var(--el-border-color)}.gi-card-body[data-v-c2f199fb]{padding:var(--card-padding-x);box-sizing:border-box;overflow:hidden;height:100%}.gi-card-footer[data-v-c2f199fb]{padding:var(--card-padding-y) var(--card-padding-x);border-top:1px solid var(--el-border-color);box-sizing:border-box}.gi-card--full .gi-card-body[data-v-c2f199fb]{flex:1;display:flex;flex-direction:column}.gi-card--inner .gi-card-header[data-v-c2f199fb],.gi-card--inner .gi-card-body[data-v-c2f199fb],.gi-card--inner .gi-card-footer[data-v-c2f199fb]{padding-left:0;padding-right:0}.gi-card--small .gi-card-header[data-v-c2f199fb]{height:36px;padding:0 var(--card-padding-x-small)}.gi-card--small .gi-card-header__title[data-v-c2f199fb]{font-size:14px}.gi-card--small .gi-card-body[data-v-c2f199fb]{padding:var(--card-padding-x-small)}.gi-card--small .gi-card-footer[data-v-c2f199fb]{padding:var(--card-padding-y-small) var(--card-padding-x-small)}[data-v-079a9f8e] .el-form-item{margin-bottom:0}[data-v-079a9f8e] .el-form-item .el-form-item__label{display:none}[data-v-079a9f8e] .column-required .cell{position:relative}[data-v-079a9f8e] .column-required .cell:after{content:"*";color:red;margin-left:2px}.gi-grid[data-v-4f2b02b0]{display:grid}[data-v-cd21cbfd] .el-button+.el-button{margin-left:0}[data-v-cd21cbfd] .el-select__wrapper{box-shadow:none;border:1px solid var(--el-border-color)}[data-v-cd21cbfd] .el-select__wrapper.is-focused{box-shadow:none;border-color:var(--el-color-primary)}[data-v-cd21cbfd] .el-select__wrapper.is-hovering:not(.is-focused){box-shadow:none;border-color:var(--el-border-color-hover)}.gi-input-group[data-v-cd21cbfd]{display:flex}.gi-input-group[data-v-cd21cbfd]>*:not(:last-child){margin-right:-1px}.gi-input-group[data-v-cd21cbfd]>*:first-child:last-child{border-radius:var(--el-border-radius-base)}.gi-input-group[data-v-cd21cbfd]>*:first-child:last-child .el-input__wrapper,.gi-input-group[data-v-cd21cbfd]>*:first-child:last-child .el-select__wrapper{border-radius:var(--el-border-radius-base)}.gi-input-group[data-v-cd21cbfd]>*:not(:first-child):not(:last-child){border-radius:0}.gi-input-group[data-v-cd21cbfd]>*:not(:first-child):not(:last-child) .el-input__wrapper{border-radius:0}.gi-input-group[data-v-cd21cbfd]>*:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.gi-input-group[data-v-cd21cbfd]>*:first-child .el-input__wrapper,.gi-input-group[data-v-cd21cbfd]>*:first-child .el-select__wrapper{border-top-right-radius:0;border-bottom-right-radius:0}.gi-input-group[data-v-cd21cbfd]>*:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.gi-input-group[data-v-cd21cbfd]>*:last-child .el-input__wrapper,.gi-input-group[data-v-cd21cbfd]>*:last-child .el-select__wrapper{border-top-left-radius:0;border-bottom-left-radius:0}.gi-input-group[data-v-cd21cbfd]>*:hover{z-index:1}.gi-input-group[data-v-cd21cbfd]>* .el-input__wrapper.is-focus,.gi-input-group[data-v-cd21cbfd]>* .el-select__wrapper.is-focused{z-index:2}[data-v-788824ed] .el-button{padding-right:12px;padding-left:12px}.el-form[data-v-c2aac7b9]{width:100%}[data-v-c2aac7b9] .el-form-item{align-items:center}[data-v-c2aac7b9] .el-form-item .el-form-item__label{height:inherit;line-height:inherit}[data-v-c2aac7b9] .hide-label .el-form-item__label{display:none}.gi-form-item__content[data-v-c2aac7b9]{width:100%;display:flex}.gi-form-item__component[data-v-c2aac7b9]{flex:1}.gi-form-item__tip[data-v-c2aac7b9]{line-height:1.5;color:var(--el-color-info-light-3)}.gi-form-item__extra[data-v-c2aac7b9]{margin-left:6px}.gi-form__search-btns[data-v-c2aac7b9],.gi-form--search[data-v-c2aac7b9] .el-form-item{margin-bottom:8px}[data-v-c2aac7b9] .w-full,[data-v-c2aac7b9] .w-full .el-date-editor{width:100%}.gi-split-button[data-v-097d86cb]{position:absolute;top:50%;transform:translateY(-50%);display:flex;justify-content:center;align-items:center;z-index:9;border:1px solid var(--el-border-color);background-color:var(--el-bg-color);box-sizing:border-box;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);will-change:transform,background-color,border-color}.gi-split-button--disabled[data-v-097d86cb]{cursor:not-allowed;opacity:.6;pointer-events:none}.gi-split-button--default[data-v-097d86cb]{width:18px;height:40px;left:0;box-shadow:2px 0 6px #0000001a}.gi-split-button--circle[data-v-097d86cb]{width:24px;height:24px;border-radius:50%;left:-12px;overflow:hidden;box-shadow:0 4px 10px #0000001a}[data-v-ae1c9bf4] .el-splitter-bar__dragger-horizontal:before,[data-v-ae1c9bf4] .el-splitter-bar__dragger-horizontal:after{width:1px}.gi-page-layout[data-v-ae1c9bf4]{flex:1;width:100%;height:100%;display:flex;overflow:hidden;background-color:var(--el-bg-color)}.gi-page-layout--bordered[data-v-ae1c9bf4]{border:1px solid var(--el-border-color)}.gi-page-layout__left[data-v-ae1c9bf4]{width:100%;height:100%}.gi-page-layout__right[data-v-ae1c9bf4]{flex:1;height:100%;display:flex;flex-direction:column;overflow:hidden;position:relative}.gi-page-layout__header[data-v-ae1c9bf4]{padding:var(--padding-x);padding-bottom:0;border-bottom:1px solid var(--el-border-color);box-sizing:border-box}.gi-page-layout__tool[data-v-ae1c9bf4]{width:100%;padding:var(--padding-x);padding-bottom:0;display:flex;justify-content:end;align-items:center;box-sizing:border-box}.gi-page-layout__body[data-v-ae1c9bf4]{flex:1;padding:var(--padding-x);height:100%;display:flex;flex-direction:column;overflow:hidden;box-sizing:border-box}.gi-page-layout__split[data-v-ae1c9bf4]{width:0;height:auto;position:relative}.gi-page-layout--has-header .gi-page-layout__tool[data-v-ae1c9bf4],.gi-page-layout--has-header .gi-page-layout__body[data-v-ae1c9bf4],.gi-page-layout--has-tool .gi-page-layout__body[data-v-ae1c9bf4]{padding-top:var(--padding-y)}.gi-page-layout--collapsing[data-v-ae1c9bf4] .el-splitter-panel{transition:flex-basis .3s}[data-v-b15a0f4d] .el-pagination__rightwrapper{flex:auto}.gi-table-pagination[data-v-b15a0f4d]{margin-top:10px}[data-v-81f370ec] .el-tabs__nav-prev,[data-v-81f370ec] .el-tabs__nav-next{height:100%;display:flex;align-items:center;justify-content:center}.gi-tabs[data-v-81f370ec]{width:100%;padding:0 var(--padding-x);display:flex;align-items:center;border-bottom:1px solid var(--el-border-color);box-sizing:border-box;background-color:var(--el-bg-color)}.gi-tabs__default[data-v-81f370ec]{flex:1;overflow:hidden}.gi-tabs__default[data-v-81f370ec] .el-tabs__header{margin-bottom:0}.gi-tabs__default[data-v-81f370ec] .el-tabs__header .el-tabs__nav-wrap:after{display:none}.gi-tabs__default[data-v-81f370ec] .el-tabs__active-bar{bottom:1px}.gi-tabs__extra[data-v-81f370ec]{margin-left:10px;align-self:flex-start}[data-v-81f370ec] .el-tabs--card>.el-tabs__header{border-bottom:none}[data-v-81f370ec] .el-tabs--border-card{border-bottom:none}[data-v-81f370ec] .el-tabs--border-card>.el-tabs__content{display:none}[data-v-81f370ec] .el-tabs--border-card>.el-tabs__header{border-bottom:none}.gi-tabs--small[data-v-81f370ec]{padding:0 var(--padding-x-small)}.gi-tabs--small[data-v-81f370ec] .el-tabs{--el-tabs-header-height: 32px}.gi-tabs--small[data-v-81f370ec] .el-tabs .el-tabs__item{font-size:12px}.gi-tabs--inner[data-v-81f370ec]{padding:0}body{--padding: 14px;--margin: 14px;--padding-x: 14px;--padding-x-small: 10px;--padding-y: 10px;--padding-y-small: 6px}.gi-card-title .gi-card-header__title{padding-left:8px;position:relative}.gi-card-title .gi-card-header__title:before{content:"";width:4px;height:20px;position:absolute;left:0;top:50%;transform:translateY(-50%);background-color:var(--el-color-primary);border-radius:0 4px 4px 0}.gi-w-full{width:100%}.gi-h-full{height:100%}.gi-line-1{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.gi-line-2{line-clamp:2;-webkit-line-clamp:2}.gi-line-3{line-clamp:3;-webkit-line-clamp:3}.gi-line-4{line-clamp:4;-webkit-line-clamp:4}.gi-line-5{line-clamp:5;-webkit-line-clamp:5}.gi-line-2,.gi-line-3,.gi-line-4,.gi-line-5{overflow:hidden;word-break:break-all;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical}.gi-mt{margin-top:var(--margin)}.gi-mb{margin-bottom:var(--margin)}.gi-ml{margin-left:var(--margin)}.gi-mr{margin-right:var(--margin)}.gi-mx{margin-left:var(--margin);margin-right:var(--margin)}.gi-my{margin-top:var(--margin);margin-bottom:var(--margin)}.gi-m0{margin:0!important}.gi-pt{padding-top:var(--padding)}.gi-pb{padding-bottom:var(--padding)}.gi-pl{padding-left:var(--padding)}.gi-pr{padding-right:var(--padding)}.gi-px{padding-left:var(--padding);padding-right:var(--padding)}.gi-py{padding-top:var(--padding);padding-bottom:var(--padding)}.gi-p0,.el-dialog{padding:0!important}.el-dialog.is-fullscreen{overflow:hidden;display:inline-flex;flex-direction:column}.el-dialog.is-fullscreen .el-dialog__body{flex:1;overflow-y:auto}.el-dialog .el-dialog__header{height:48px;padding-left:var(--el-dialog-padding-primary);padding-bottom:0;display:flex;align-items:center;border-bottom:1px solid var(--el-border-color)}.el-dialog .el-dialog__body{padding:var(--el-dialog-padding-primary)}.el-dialog .el-dialog__footer{padding:12px var(--el-dialog-padding-primary);border-top:1px solid var(--el-border-color)}.el-dialog.gi-dialog--simple .el-dialog__header{border-bottom:none}.el-dialog.gi-dialog--simple .el-dialog__footer{border-top:none}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { }
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gi-component",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"description": "Vue3中基于Element Plus二次封装基础组件库",
|
|
6
|
+
"author": "lin",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/lin-97/gi-component.git"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"element-plus",
|
|
14
|
+
"vitepress",
|
|
15
|
+
"vue3",
|
|
16
|
+
"gi-component",
|
|
17
|
+
"二次封装组件",
|
|
18
|
+
"封装组件"
|
|
19
|
+
],
|
|
20
|
+
"main": "dist/index.umd.js",
|
|
21
|
+
"module": "dist/index.es.js",
|
|
22
|
+
"types": "dist/index.d.ts",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"packages"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "vite --host",
|
|
29
|
+
"docs:dev": "cd docs && pnpm dev",
|
|
30
|
+
"docs:build": "cd docs && pnpm build",
|
|
31
|
+
"docs:preview": "cd docs && pnpm preview",
|
|
32
|
+
"build:lib": "vite build --mode lib",
|
|
33
|
+
"build:docs": "cd docs && pnpm build"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"element-plus": "^2.11.2",
|
|
37
|
+
"vue": "^3.5.15"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@antfu/eslint-config": "^5.2.1",
|
|
41
|
+
"@element-plus/icons-vue": "^2.3.1",
|
|
42
|
+
"@vitejs/plugin-vue": "^5.2.4",
|
|
43
|
+
"@vitejs/plugin-vue-jsx": "^4.2.0",
|
|
44
|
+
"element-plus": "^2.11.2",
|
|
45
|
+
"eslint": "^9.27.0",
|
|
46
|
+
"sass": "^1.89.0",
|
|
47
|
+
"sass-loader": "^16.0.5",
|
|
48
|
+
"terser": "^5.44.0",
|
|
49
|
+
"typescript": "^5.8.3",
|
|
50
|
+
"unplugin-vue-components": "^28.8.0",
|
|
51
|
+
"vite": "6.3.5",
|
|
52
|
+
"vite-plugin-dts": "^4.5.4",
|
|
53
|
+
"vue": "^3.5.15",
|
|
54
|
+
"vue-tsc": "^2.2.10"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-button :class="b('button')" v-bind="bindProps" @click="(e: MouseEvent) => emit('click', e)">
|
|
3
|
+
<slot>{{ btnText }}</slot>
|
|
4
|
+
</el-button>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import type { ButtonProps as ElButtonProps } from 'element-plus';
|
|
9
|
+
import type { ButtonProps } from './type.ts';
|
|
10
|
+
import {
|
|
11
|
+
Delete,
|
|
12
|
+
Download,
|
|
13
|
+
Edit,
|
|
14
|
+
Plus,
|
|
15
|
+
Printer,
|
|
16
|
+
Search,
|
|
17
|
+
Upload
|
|
18
|
+
} from '@element-plus/icons-vue';
|
|
19
|
+
import { computed, useAttrs } from 'vue';
|
|
20
|
+
import { useBemClass } from '../../../hooks';
|
|
21
|
+
|
|
22
|
+
const props = withDefaults(defineProps<ButtonProps>(), {
|
|
23
|
+
type: ''
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const emit = defineEmits<{
|
|
27
|
+
(e: 'click', event: MouseEvent): void;
|
|
28
|
+
}>();
|
|
29
|
+
|
|
30
|
+
const attrs = useAttrs();
|
|
31
|
+
|
|
32
|
+
const { b } = useBemClass();
|
|
33
|
+
|
|
34
|
+
const obj: Record<string, { btnProps: Partial<ButtonProps>; btnText: string }> =
|
|
35
|
+
{
|
|
36
|
+
add: { btnProps: { icon: Plus, type: 'primary' }, btnText: '新增' },
|
|
37
|
+
edit: { btnProps: { icon: Edit, type: 'primary' }, btnText: '编辑' },
|
|
38
|
+
delete: { btnProps: { icon: Delete, type: 'danger' }, btnText: '删除' },
|
|
39
|
+
search: { btnProps: { icon: Search, type: 'primary' }, btnText: '搜索' },
|
|
40
|
+
reset: { btnProps: { type: undefined }, btnText: '重置' },
|
|
41
|
+
upload: { btnProps: { icon: Upload, type: 'primary' }, btnText: '上传' },
|
|
42
|
+
download: {
|
|
43
|
+
btnProps: { icon: Download, type: 'primary' },
|
|
44
|
+
btnText: '下载'
|
|
45
|
+
},
|
|
46
|
+
print: { btnProps: { icon: Printer, type: 'primary' }, btnText: '打印' }
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const bindProps = computed(() => {
|
|
50
|
+
const btnProps = obj?.[props.type]?.btnProps || { type: props.type };
|
|
51
|
+
return { ...attrs, ...props, ...btnProps } as Omit<ElButtonProps, 'type'>;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const btnText = computed(() => {
|
|
55
|
+
return obj[props.type].btnText;
|
|
56
|
+
});
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<style lang="scss" scoped></style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ButtonProps as ElButtonProps } from 'element-plus';
|
|
2
|
+
|
|
3
|
+
export interface ButtonProps extends Partial<Omit<ElButtonProps, 'type'>> {
|
|
4
|
+
type?:
|
|
5
|
+
| 'add'
|
|
6
|
+
| 'edit'
|
|
7
|
+
| 'delete'
|
|
8
|
+
| 'search'
|
|
9
|
+
| 'reset'
|
|
10
|
+
| 'upload'
|
|
11
|
+
| 'download'
|
|
12
|
+
| 'print'
|
|
13
|
+
| ''
|
|
14
|
+
| ElButtonProps['type'];
|
|
15
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="getCardClass">
|
|
3
|
+
<section :class="getHeaderClass" :style="props.headerStyle">
|
|
4
|
+
<div :class="b('card-header__title')">
|
|
5
|
+
<slot name="title">{{ props.title }}</slot>
|
|
6
|
+
</div>
|
|
7
|
+
<div :class="b('card-header__extra')">
|
|
8
|
+
<slot name="extra">{{ props.extra }}</slot>
|
|
9
|
+
</div>
|
|
10
|
+
</section>
|
|
11
|
+
<section :class="b('card-body')" :style="props.bodyStyle">
|
|
12
|
+
<slot></slot>
|
|
13
|
+
</section>
|
|
14
|
+
<section v-if="slot.footer" :class="b('card-footer')">
|
|
15
|
+
<slot name="footer"></slot>
|
|
16
|
+
</section>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
import type { CardProps } from './type';
|
|
22
|
+
import { computed, useSlots } from 'vue';
|
|
23
|
+
import { useBemClass } from '../../../hooks';
|
|
24
|
+
|
|
25
|
+
const props = withDefaults(defineProps<CardProps>(), {
|
|
26
|
+
title: '',
|
|
27
|
+
extra: '',
|
|
28
|
+
size: 'middle' as const,
|
|
29
|
+
bordered: false,
|
|
30
|
+
headerBordered: true,
|
|
31
|
+
headerStyle: () => ({}),
|
|
32
|
+
bodyStyle: () => ({}),
|
|
33
|
+
inner: false
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
defineSlots<{
|
|
37
|
+
default: () => void;
|
|
38
|
+
title: () => void;
|
|
39
|
+
extra: () => void;
|
|
40
|
+
footer: () => void;
|
|
41
|
+
}>();
|
|
42
|
+
|
|
43
|
+
const slot = useSlots();
|
|
44
|
+
const { b } = useBemClass();
|
|
45
|
+
|
|
46
|
+
const getCardClass = computed(() => {
|
|
47
|
+
const arr: string[] = [b('card')];
|
|
48
|
+
if (props.bordered) {
|
|
49
|
+
arr.push(b('card--bordered'));
|
|
50
|
+
}
|
|
51
|
+
if (props.inner) {
|
|
52
|
+
arr.push(b('card--inner'));
|
|
53
|
+
}
|
|
54
|
+
arr.push(b(`card--${props.size}`));
|
|
55
|
+
return arr.join(' ');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const getHeaderClass = computed(() => {
|
|
59
|
+
const arr: string[] = [b('card-header')];
|
|
60
|
+
if (props.headerBordered) {
|
|
61
|
+
arr.push(b('card-header--bordered'));
|
|
62
|
+
}
|
|
63
|
+
return arr.join(' ');
|
|
64
|
+
});
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<style lang="scss" scoped>
|
|
68
|
+
@use '../../../styles/var.scss' as a;
|
|
69
|
+
|
|
70
|
+
.#{a.$prefix}-card {
|
|
71
|
+
background-color: var(--el-bg-color);
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
box-sizing: border-box;
|
|
76
|
+
--card-padding-x: var(--padding-x);
|
|
77
|
+
--card-padding-x-small: var(--padding-x-small);
|
|
78
|
+
--card-padding-y: var(--padding-y);
|
|
79
|
+
--card-padding-y-small: var(--padding-y-small);
|
|
80
|
+
|
|
81
|
+
&--bordered {
|
|
82
|
+
border: 1px solid var(--el-border-color);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.#{a.$prefix}-card-header {
|
|
87
|
+
height: 46px;
|
|
88
|
+
padding: 0 var(--card-padding-x);
|
|
89
|
+
display: flex;
|
|
90
|
+
justify-content: space-between;
|
|
91
|
+
align-items: center;
|
|
92
|
+
color: var(--el-text-color-primary);
|
|
93
|
+
box-sizing: border-box;
|
|
94
|
+
position: relative;
|
|
95
|
+
flex-shrink: 0;
|
|
96
|
+
|
|
97
|
+
&__title {
|
|
98
|
+
position: relative;
|
|
99
|
+
line-height: 1.3em;
|
|
100
|
+
overflow: hidden;
|
|
101
|
+
white-space: nowrap;
|
|
102
|
+
text-overflow: ellipsis;
|
|
103
|
+
box-sizing: border-box;
|
|
104
|
+
font-weight: 500;
|
|
105
|
+
font-size: 16px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
&__extra {
|
|
109
|
+
display: flex;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
&--bordered {
|
|
113
|
+
border-bottom: 1px solid var(--el-border-color);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.#{a.$prefix}-card-body {
|
|
118
|
+
padding: var(--card-padding-x);
|
|
119
|
+
box-sizing: border-box;
|
|
120
|
+
overflow: hidden;
|
|
121
|
+
height: 100%;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.#{a.$prefix}-card-footer {
|
|
125
|
+
padding: var(--card-padding-y) var(--card-padding-x);
|
|
126
|
+
box-sizing: border-box;
|
|
127
|
+
border-top: 1px solid var(--el-border-color);
|
|
128
|
+
box-sizing: border-box;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.#{a.$prefix}-card--full {
|
|
132
|
+
.#{a.$prefix}-card-body {
|
|
133
|
+
flex: 1;
|
|
134
|
+
display: flex;
|
|
135
|
+
flex-direction: column;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.#{a.$prefix}-card--inner {
|
|
140
|
+
.#{a.$prefix}-card-header,
|
|
141
|
+
.#{a.$prefix}-card-body,
|
|
142
|
+
.#{a.$prefix}-card-footer {
|
|
143
|
+
padding-left: 0;
|
|
144
|
+
padding-right: 0;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.#{a.$prefix}-card--small {
|
|
149
|
+
.#{a.$prefix}-card-header {
|
|
150
|
+
height: 36px;
|
|
151
|
+
padding: 0 var(--card-padding-x-small);
|
|
152
|
+
|
|
153
|
+
&__title {
|
|
154
|
+
font-size: 14px;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.#{a.$prefix}-card-body {
|
|
159
|
+
padding: var(--card-padding-x-small);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.#{a.$prefix}-card-footer {
|
|
163
|
+
padding: var(--card-padding-y-small) var(--card-padding-x-small);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CSSProperties } from 'vue';
|
|
2
|
+
|
|
3
|
+
export interface CardProps {
|
|
4
|
+
title?: string;
|
|
5
|
+
extra?: string;
|
|
6
|
+
bordered?: boolean;
|
|
7
|
+
size?: 'small' | 'middle';
|
|
8
|
+
headerBordered?: boolean;
|
|
9
|
+
headerStyle?: CSSProperties;
|
|
10
|
+
bodyStyle?: CSSProperties;
|
|
11
|
+
inner?: boolean; // 内嵌模式
|
|
12
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { DialogInstance } from '../index';
|
|
2
|
+
import ElementPlus from 'element-plus';
|
|
3
|
+
import { createApp, h, ref } from 'vue';
|
|
4
|
+
import GiDialog from './dialog.vue';
|
|
5
|
+
|
|
6
|
+
type DialogOptions = Partial<DialogInstance['$props']>;
|
|
7
|
+
|
|
8
|
+
export interface DialogReturnObject {
|
|
9
|
+
close: () => void;
|
|
10
|
+
update: (newProps?: Record<string, any>) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const DEF_OPTIONS: DialogOptions = {
|
|
14
|
+
// width: '600px',
|
|
15
|
+
// center: false,
|
|
16
|
+
// footer: true,
|
|
17
|
+
// closeOnClickModal: true
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function createDialog() {
|
|
21
|
+
const Dialog = {
|
|
22
|
+
_context: {},
|
|
23
|
+
// 核心创建方法
|
|
24
|
+
create(options: DialogOptions): DialogReturnObject {
|
|
25
|
+
const mergedOptions = { ...DEF_OPTIONS, ...options };
|
|
26
|
+
// 创建容器
|
|
27
|
+
const container = document.createElement('div');
|
|
28
|
+
document.body.appendChild(container);
|
|
29
|
+
|
|
30
|
+
// 状态管理
|
|
31
|
+
const visible = ref(true);
|
|
32
|
+
const dialogOptions = ref(mergedOptions || {});
|
|
33
|
+
|
|
34
|
+
// 创建弹窗应用
|
|
35
|
+
const dialogApp = createApp({
|
|
36
|
+
setup() {
|
|
37
|
+
// 关闭处理
|
|
38
|
+
const closed = () => {
|
|
39
|
+
dialogApp.unmount();
|
|
40
|
+
container.remove();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return () =>
|
|
44
|
+
h(GiDialog, {
|
|
45
|
+
...dialogOptions.value,
|
|
46
|
+
modelValue: visible.value,
|
|
47
|
+
'onUpdate:modelValue': (val: boolean) => (visible.value = val),
|
|
48
|
+
onClosed: () => closed()
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
dialogApp.use(ElementPlus);
|
|
54
|
+
|
|
55
|
+
// 继承主应用的上下文
|
|
56
|
+
Object.assign(dialogApp._context, Dialog._context);
|
|
57
|
+
|
|
58
|
+
// 挂载
|
|
59
|
+
dialogApp.mount(container);
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
/** 关闭对话框 */
|
|
63
|
+
close: () => {
|
|
64
|
+
visible.value = false;
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
dialogApp.unmount();
|
|
67
|
+
container.remove();
|
|
68
|
+
}, 300);
|
|
69
|
+
},
|
|
70
|
+
/** 更新对话框 */
|
|
71
|
+
update: (newProps?: Record<string, any>) => {
|
|
72
|
+
dialogOptions.value = { ...dialogOptions.value, ...newProps };
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/** 对话框-打开 */
|
|
78
|
+
open(options: DialogOptions) {
|
|
79
|
+
return this.create(options);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return Dialog;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 默认导出实例
|
|
87
|
+
export const Dialog = createDialog();
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-dialog
|
|
3
|
+
v-bind="dialogProps"
|
|
4
|
+
v-model="visible"
|
|
5
|
+
:class="getClass"
|
|
6
|
+
:title="props.title"
|
|
7
|
+
:style="{ maxWidth: !props.fullscreen ? '480px' : '100%', ...props.style }"
|
|
8
|
+
>
|
|
9
|
+
<slot>
|
|
10
|
+
<template v-if="typeof props.content === 'string'">
|
|
11
|
+
<p>{{ props.content }}</p>
|
|
12
|
+
</template>
|
|
13
|
+
<template v-if="typeof props.content === 'function'">
|
|
14
|
+
<component :is="props?.content?.()"></component>
|
|
15
|
+
</template>
|
|
16
|
+
</slot>
|
|
17
|
+
<template v-if="props.footer" #footer>
|
|
18
|
+
<slot name="footer">
|
|
19
|
+
<template v-if="typeof props.footer === 'boolean'">
|
|
20
|
+
<el-space :size="10">
|
|
21
|
+
<el-button v-bind="props.cancelButtonProps" @click="handleCancel">{{
|
|
22
|
+
props.cancelText
|
|
23
|
+
}}</el-button>
|
|
24
|
+
<el-button
|
|
25
|
+
type="primary"
|
|
26
|
+
v-bind="props.okButtonProps"
|
|
27
|
+
:loading="okLoading"
|
|
28
|
+
@click="handleOk"
|
|
29
|
+
>
|
|
30
|
+
{{ props.okText }}
|
|
31
|
+
</el-button>
|
|
32
|
+
</el-space>
|
|
33
|
+
</template>
|
|
34
|
+
<template v-else>
|
|
35
|
+
<component :is="props.footer()"></component>
|
|
36
|
+
</template>
|
|
37
|
+
</slot>
|
|
38
|
+
</template>
|
|
39
|
+
</el-dialog>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<script lang="ts" setup>
|
|
43
|
+
import type { VNode } from 'vue';
|
|
44
|
+
import type { DialogProps } from './type';
|
|
45
|
+
import { computed, defineProps, defineSlots, ref } from 'vue';
|
|
46
|
+
import { useBemClass } from '../../../hooks';
|
|
47
|
+
|
|
48
|
+
const visible = defineModel('modelValue', {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const props = withDefaults(defineProps<DialogProps>(), {
|
|
54
|
+
closeOnClickModal: true,
|
|
55
|
+
showClose: true,
|
|
56
|
+
footer: true,
|
|
57
|
+
okText: '确认',
|
|
58
|
+
cancelText: '取消',
|
|
59
|
+
width: 'calc(100% - 20px)',
|
|
60
|
+
alignCenter: true
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
defineSlots<{
|
|
64
|
+
title: () => VNode;
|
|
65
|
+
footer: () => VNode;
|
|
66
|
+
default: () => VNode;
|
|
67
|
+
}>();
|
|
68
|
+
|
|
69
|
+
const { b } = useBemClass();
|
|
70
|
+
|
|
71
|
+
const getClass = computed(() => {
|
|
72
|
+
const arr: string[] = [b('dialog')];
|
|
73
|
+
if (props.simple) {
|
|
74
|
+
arr.push(b('dialog--simple'));
|
|
75
|
+
}
|
|
76
|
+
return arr.join(' ');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const dialogProps = computed(() => {
|
|
80
|
+
return {
|
|
81
|
+
...props,
|
|
82
|
+
content: undefined,
|
|
83
|
+
footer: undefined,
|
|
84
|
+
okText: undefined,
|
|
85
|
+
cancelText: undefined,
|
|
86
|
+
okButtonProps: undefined,
|
|
87
|
+
cancelButtonProps: undefined,
|
|
88
|
+
onOk: undefined,
|
|
89
|
+
onBeforeOk: undefined,
|
|
90
|
+
onCancel: undefined,
|
|
91
|
+
simple: undefined
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const okLoading = ref(false);
|
|
96
|
+
|
|
97
|
+
const handleCancel = () => {
|
|
98
|
+
props.onCancel?.();
|
|
99
|
+
visible.value = false;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const handleOk = async () => {
|
|
103
|
+
if (props.onBeforeOk) {
|
|
104
|
+
try {
|
|
105
|
+
okLoading.value = true;
|
|
106
|
+
const flag = await props.onBeforeOk();
|
|
107
|
+
okLoading.value = false;
|
|
108
|
+
if (flag) {
|
|
109
|
+
visible.value = false;
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error('error', error);
|
|
113
|
+
okLoading.value = false;
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
props.onOk?.();
|
|
117
|
+
visible.value = false;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
</script>
|
|
121
|
+
|
|
122
|
+
<style lang="scss" scoped></style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ButtonProps, DialogProps as ElDialogProps } from 'element-plus';
|
|
2
|
+
import type { CSSProperties, VNode } from 'vue';
|
|
3
|
+
|
|
4
|
+
export interface DialogProps extends Partial<ElDialogProps> {
|
|
5
|
+
content?: string | (() => VNode);
|
|
6
|
+
footer?: boolean | (() => VNode);
|
|
7
|
+
okText?: string;
|
|
8
|
+
cancelText?: string;
|
|
9
|
+
okButtonProps?: Partial<ButtonProps>;
|
|
10
|
+
cancelButtonProps?: Partial<ButtonProps>;
|
|
11
|
+
style?: CSSProperties;
|
|
12
|
+
simple?: boolean; // 简单模式
|
|
13
|
+
onOk?: () => void;
|
|
14
|
+
onBeforeOk?: () => Promise<boolean>;
|
|
15
|
+
onCancel?: () => void;
|
|
16
|
+
}
|