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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +36 -0
  3. package/dist/dist/index.es.js +2241 -0
  4. package/dist/dist/index.es.js.map +1 -0
  5. package/dist/dist/index.umd.js +2 -0
  6. package/dist/dist/index.umd.js.map +1 -0
  7. package/dist/gi.css +1 -0
  8. package/dist/index.d.ts +1 -0
  9. package/package.json +56 -0
  10. package/packages/components/button/index.ts +5 -0
  11. package/packages/components/button/src/button.vue +59 -0
  12. package/packages/components/button/src/type.ts +15 -0
  13. package/packages/components/card/index.ts +5 -0
  14. package/packages/components/card/src/card.vue +166 -0
  15. package/packages/components/card/src/type.ts +12 -0
  16. package/packages/components/dialog/index.ts +6 -0
  17. package/packages/components/dialog/src/dialog.ts +87 -0
  18. package/packages/components/dialog/src/dialog.vue +122 -0
  19. package/packages/components/dialog/src/type.ts +16 -0
  20. package/packages/components/edit-table/index.ts +5 -0
  21. package/packages/components/edit-table/src/edit-table.vue +207 -0
  22. package/packages/components/edit-table/src/type.ts +69 -0
  23. package/packages/components/form/index.ts +5 -0
  24. package/packages/components/form/src/form.vue +465 -0
  25. package/packages/components/form/src/type.ts +98 -0
  26. package/packages/components/grid/index.ts +8 -0
  27. package/packages/components/grid/src/context.ts +30 -0
  28. package/packages/components/grid/src/grid-item.vue +143 -0
  29. package/packages/components/grid/src/grid.vue +151 -0
  30. package/packages/components/grid/src/hook/use-index.ts +63 -0
  31. package/packages/components/grid/src/hook/use-responsive-state.ts +66 -0
  32. package/packages/components/grid/src/hook/use-responsive-value.ts +36 -0
  33. package/packages/components/grid/src/interface.ts +74 -0
  34. package/packages/components/grid/src/type.ts +0 -0
  35. package/packages/components/grid/src/utils/global-config.ts +6 -0
  36. package/packages/components/grid/src/utils/index.ts +73 -0
  37. package/packages/components/grid/src/utils/is.ts +9 -0
  38. package/packages/components/grid/src/utils/responsive-observe.ts +135 -0
  39. package/packages/components/input-group/index.ts +5 -0
  40. package/packages/components/input-group/src/input-group.vue +92 -0
  41. package/packages/components/input-group/src/type.ts +1 -0
  42. package/packages/components/input-search/index.ts +5 -0
  43. package/packages/components/input-search/src/input-search.vue +62 -0
  44. package/packages/components/input-search/src/type.ts +6 -0
  45. package/packages/components/page-layout/index.ts +5 -0
  46. package/packages/components/page-layout/src/page-layout.vue +180 -0
  47. package/packages/components/page-layout/src/split-button.vue +106 -0
  48. package/packages/components/page-layout/src/type.ts +12 -0
  49. package/packages/components/table/index.ts +5 -0
  50. package/packages/components/table/src/TableColumn.vue +49 -0
  51. package/packages/components/table/src/table.vue +85 -0
  52. package/packages/components/table/src/type.ts +22 -0
  53. package/packages/components/tabs/index.ts +5 -0
  54. package/packages/components/tabs/src/tabs.vue +148 -0
  55. package/packages/components/tabs/src/type.ts +15 -0
  56. package/packages/components.d.ts +26 -0
  57. package/packages/hooks/index.ts +1 -0
  58. package/packages/hooks/useBemClass.ts +11 -0
  59. package/packages/index.ts +78 -0
  60. package/packages/styles/index.scss +176 -0
  61. package/packages/styles/var.scss +1 -0
  62. package/packages/utils/createSelectDialog.ts +67 -0
  63. 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}
@@ -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,5 @@
1
+ import Button from './src/button.vue';
2
+
3
+ export type ButtonInstance = InstanceType<typeof Button>;
4
+ export * from './src/type';
5
+ export default Button;
@@ -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,5 @@
1
+ import Card from './src/card.vue';
2
+
3
+ export type CardInstance = InstanceType<typeof Card>;
4
+ export * from './src/type';
5
+ export default Card;
@@ -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,6 @@
1
+ import Dialog from './src/dialog.vue';
2
+
3
+ export type DialogInstance = InstanceType<typeof Dialog>;
4
+ export * from './src/dialog';
5
+ export * from './src/type';
6
+ export default Dialog;
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ import EditTable from './src/edit-table.vue';
2
+
3
+ export type EditTableInstance = InstanceType<typeof EditTable>;
4
+ export * from './src/type';
5
+ export default EditTable;