@vunk/plus 1.1.4 → 1.2.0
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/components/SendOutlined.mjs +1319 -0
- package/components/avatar/index.d.ts +4 -0
- package/components/avatar/index.mjs +49 -0
- package/components/avatar/src/ctx.d.ts +18 -0
- package/components/avatar/src/index.vue.d.ts +180 -0
- package/components/avatar/src/types.d.ts +1 -0
- package/components/recorder-button/index.css +72 -0
- package/components/recorder-button/index.d.ts +4 -0
- package/components/recorder-button/index.mjs +319 -0
- package/components/recorder-button/src/ctx.d.ts +19 -0
- package/components/recorder-button/src/index.vue.d.ts +309 -0
- package/components/recorder-button/src/speech-to-text.d.ts +1 -0
- package/components/recorder-button/src/types.d.ts +6 -0
- package/components/sender/index.css +29 -0
- package/components/sender/index.d.ts +4 -0
- package/components/sender/index.mjs +172 -0
- package/components/sender/src/ctx.d.ts +21 -0
- package/components/sender/src/index.vue.d.ts +484 -0
- package/components/sender/src/types.d.ts +1 -0
- package/components/speech-button/index.css +10 -0
- package/components/speech-button/index.d.ts +4 -0
- package/components/speech-button/index.mjs +131 -0
- package/components/speech-button/src/RecordingIcon.vue.d.ts +2 -0
- package/components/speech-button/src/ctx.d.ts +10 -0
- package/components/speech-button/src/index.vue.d.ts +22 -0
- package/components/speech-button/src/types.d.ts +1 -0
- package/components/table-columns/src/ctx.d.ts +4 -4
- package/components/table-columns/src/el-ctx.d.ts +5 -5
- package/components/table-columns/src/index.vue.d.ts +21 -21
- package/components/tables-v1/src/ctx.d.ts +24 -24
- package/components/tables-v1/src/el-ctx.d.ts +10 -10
- package/components/tables-v1/src/index.vue.d.ts +103 -103
- package/components/tables-v1-checkbox/src/ctx.d.ts +22 -22
- package/components/tables-v1-checkbox/src/index.vue.d.ts +182 -170
- package/components/vditor/src/index.vue.d.ts +5 -5
- package/composables/recorder/index.d.ts +15 -0
- package/composables/recorder/index.mjs +14478 -0
- package/index.css +114 -0
- package/package.json +30 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ElAvatar } from 'element-plus';
|
|
2
|
+
import { defineComponent, resolveComponent, openBlock, createBlock, normalizeStyle, withCtx, renderSlot } from 'vue';
|
|
3
|
+
import { _ as _export_sfc } from '../_plugin-vue_export-helper.mjs';
|
|
4
|
+
|
|
5
|
+
const props = {
|
|
6
|
+
background: {
|
|
7
|
+
default: "transparent"
|
|
8
|
+
},
|
|
9
|
+
color: {
|
|
10
|
+
default: "currentColor"
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
const emits = {};
|
|
14
|
+
|
|
15
|
+
var _sfc_main = defineComponent({
|
|
16
|
+
name: "VkAvatar",
|
|
17
|
+
components: {
|
|
18
|
+
ElAvatar
|
|
19
|
+
},
|
|
20
|
+
props,
|
|
21
|
+
emits
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
25
|
+
const _component_ElAvatar = resolveComponent("ElAvatar");
|
|
26
|
+
return openBlock(), createBlock(_component_ElAvatar, {
|
|
27
|
+
style: normalizeStyle({
|
|
28
|
+
background: _ctx.background,
|
|
29
|
+
color: _ctx.color
|
|
30
|
+
})
|
|
31
|
+
}, {
|
|
32
|
+
default: withCtx(() => [
|
|
33
|
+
renderSlot(_ctx.$slots, "default")
|
|
34
|
+
]),
|
|
35
|
+
_: 3
|
|
36
|
+
/* FORWARDED */
|
|
37
|
+
}, 8, ["style"]);
|
|
38
|
+
}
|
|
39
|
+
var VkAvatar = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__file", "/home/runner/work/vunk-plus/vunk-plus/packages/components/avatar/src/index.vue"]]);
|
|
40
|
+
|
|
41
|
+
var types = /*#__PURE__*/Object.freeze({
|
|
42
|
+
__proto__: null
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
VkAvatar.install = (app) => {
|
|
46
|
+
app.component(VkAvatar.name || "VkAvatar", VkAvatar);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export { VkAvatar, types as __VkAvatar, VkAvatar as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const props: {
|
|
2
|
+
readonly size: import("element-plus/es/utils").EpPropFinalized<readonly [NumberConstructor, StringConstructor], "" | "default" | "small" | "large", number, "", boolean>;
|
|
3
|
+
readonly shape: import("element-plus/es/utils").EpPropFinalized<StringConstructor, "circle" | "square", unknown, "circle", boolean>;
|
|
4
|
+
readonly icon: {
|
|
5
|
+
readonly type: import("vue").PropType<unknown>;
|
|
6
|
+
readonly required: false;
|
|
7
|
+
readonly validator: (val: unknown) => boolean;
|
|
8
|
+
__epPropKey: true;
|
|
9
|
+
};
|
|
10
|
+
readonly src: import("element-plus/es/utils").EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
|
|
11
|
+
readonly alt: StringConstructor;
|
|
12
|
+
readonly srcSet: StringConstructor;
|
|
13
|
+
readonly fit: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => any) | (() => ObjectFitProperty) | ((new (...args: any[]) => any) | (() => ObjectFitProperty))[], unknown, unknown, "cover", boolean>;
|
|
14
|
+
} & {
|
|
15
|
+
background: never;
|
|
16
|
+
color: never;
|
|
17
|
+
};
|
|
18
|
+
export declare const emits: {};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
2
|
+
readonly size: import("element-plus/es/utils").EpPropFinalized<readonly [NumberConstructor, StringConstructor], "" | "default" | "small" | "large", number, "", boolean>;
|
|
3
|
+
readonly shape: import("element-plus/es/utils").EpPropFinalized<StringConstructor, "circle" | "square", unknown, "circle", boolean>;
|
|
4
|
+
readonly icon: {
|
|
5
|
+
readonly type: import("vue").PropType<unknown>;
|
|
6
|
+
readonly required: false;
|
|
7
|
+
readonly validator: (val: unknown) => boolean;
|
|
8
|
+
__epPropKey: true;
|
|
9
|
+
};
|
|
10
|
+
readonly src: import("element-plus/es/utils").EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
|
|
11
|
+
readonly alt: StringConstructor;
|
|
12
|
+
readonly srcSet: StringConstructor;
|
|
13
|
+
readonly fit: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => any) | (() => ObjectFitProperty) | ((new (...args: any[]) => any) | (() => ObjectFitProperty))[], unknown, unknown, "cover", boolean>;
|
|
14
|
+
} & {
|
|
15
|
+
background: never;
|
|
16
|
+
color: never;
|
|
17
|
+
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
18
|
+
readonly size: import("element-plus/es/utils").EpPropFinalized<readonly [NumberConstructor, StringConstructor], "" | "default" | "small" | "large", number, "", boolean>;
|
|
19
|
+
readonly shape: import("element-plus/es/utils").EpPropFinalized<StringConstructor, "circle" | "square", unknown, "circle", boolean>;
|
|
20
|
+
readonly icon: {
|
|
21
|
+
readonly type: import("vue").PropType<unknown>;
|
|
22
|
+
readonly required: false;
|
|
23
|
+
readonly validator: (val: unknown) => boolean;
|
|
24
|
+
__epPropKey: true;
|
|
25
|
+
};
|
|
26
|
+
readonly src: import("element-plus/es/utils").EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
|
|
27
|
+
readonly alt: StringConstructor;
|
|
28
|
+
readonly srcSet: StringConstructor;
|
|
29
|
+
readonly fit: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => any) | (() => ObjectFitProperty) | ((new (...args: any[]) => any) | (() => ObjectFitProperty))[], unknown, unknown, "cover", boolean>;
|
|
30
|
+
} & {
|
|
31
|
+
background: never;
|
|
32
|
+
color: never;
|
|
33
|
+
}>> & Readonly<{}>, {
|
|
34
|
+
readonly size: import("element-plus").ButtonType<readonly [NumberConstructor, StringConstructor], "" | "default" | "small" | "large", number>;
|
|
35
|
+
readonly shape: import("element-plus").ButtonType<StringConstructor, "circle" | "square", unknown>;
|
|
36
|
+
readonly src: string;
|
|
37
|
+
readonly fit: any;
|
|
38
|
+
}, {}, {
|
|
39
|
+
ElAvatar: import("element-plus/es/utils").SFCWithInstall<import("vue").DefineComponent<{
|
|
40
|
+
readonly size: import("element-plus/es/utils").EpPropFinalized<readonly [NumberConstructor, StringConstructor], "" | "default" | "small" | "large", number, "", boolean>;
|
|
41
|
+
readonly shape: import("element-plus/es/utils").EpPropFinalized<StringConstructor, "circle" | "square", unknown, "circle", boolean>;
|
|
42
|
+
readonly icon: {
|
|
43
|
+
readonly type: import("vue").PropType<unknown>;
|
|
44
|
+
readonly required: false;
|
|
45
|
+
readonly validator: (val: unknown) => boolean;
|
|
46
|
+
__epPropKey: true;
|
|
47
|
+
};
|
|
48
|
+
readonly src: import("element-plus/es/utils").EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
|
|
49
|
+
readonly alt: StringConstructor;
|
|
50
|
+
readonly srcSet: StringConstructor;
|
|
51
|
+
readonly fit: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => any) | (() => any) | ((new (...args: any[]) => any) | (() => any))[], unknown, unknown, "cover", boolean>;
|
|
52
|
+
}, {
|
|
53
|
+
props: Readonly<import("@vue/shared").LooseRequired<Readonly<import("vue").ExtractPropTypes<{
|
|
54
|
+
readonly size: import("element-plus/es/utils").EpPropFinalized<readonly [NumberConstructor, StringConstructor], "" | "default" | "small" | "large", number, "", boolean>;
|
|
55
|
+
readonly shape: import("element-plus/es/utils").EpPropFinalized<StringConstructor, "circle" | "square", unknown, "circle", boolean>;
|
|
56
|
+
readonly icon: {
|
|
57
|
+
readonly type: import("vue").PropType<unknown>;
|
|
58
|
+
readonly required: false;
|
|
59
|
+
readonly validator: (val: unknown) => boolean;
|
|
60
|
+
__epPropKey: true;
|
|
61
|
+
};
|
|
62
|
+
readonly src: import("element-plus/es/utils").EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
|
|
63
|
+
readonly alt: StringConstructor;
|
|
64
|
+
readonly srcSet: StringConstructor;
|
|
65
|
+
readonly fit: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => any) | (() => any) | ((new (...args: any[]) => any) | (() => any))[], unknown, unknown, "cover", boolean>;
|
|
66
|
+
}>> & {
|
|
67
|
+
onError?: (evt: Event) => any;
|
|
68
|
+
}>>;
|
|
69
|
+
emit: (event: "error", evt: Event) => void;
|
|
70
|
+
ns: {
|
|
71
|
+
namespace: import("vue").ComputedRef<string>;
|
|
72
|
+
b: (blockSuffix?: string) => string;
|
|
73
|
+
e: (element?: string) => string;
|
|
74
|
+
m: (modifier?: string) => string;
|
|
75
|
+
be: (blockSuffix?: string, element?: string) => string;
|
|
76
|
+
em: (element?: string, modifier?: string) => string;
|
|
77
|
+
bm: (blockSuffix?: string, modifier?: string) => string;
|
|
78
|
+
bem: (blockSuffix?: string, element?: string, modifier?: string) => string;
|
|
79
|
+
is: {
|
|
80
|
+
(name: string, state: boolean): string;
|
|
81
|
+
(name: string): string;
|
|
82
|
+
};
|
|
83
|
+
cssVar: (object: Record<string, string>) => Record<string, string>;
|
|
84
|
+
cssVarName: (name: string) => string;
|
|
85
|
+
cssVarBlock: (object: Record<string, string>) => Record<string, string>;
|
|
86
|
+
cssVarBlockName: (name: string) => string;
|
|
87
|
+
};
|
|
88
|
+
hasLoadError: import("vue").Ref<boolean, boolean>;
|
|
89
|
+
avatarClass: import("vue").ComputedRef<string[]>;
|
|
90
|
+
sizeStyle: import("vue").ComputedRef<import("vue").CSSProperties>;
|
|
91
|
+
fitStyle: import("vue").ComputedRef<import("vue").CSSProperties>;
|
|
92
|
+
handleError: (e: Event) => void;
|
|
93
|
+
ElIcon: import("element-plus/es/utils").SFCWithInstall<import("vue").DefineComponent<{
|
|
94
|
+
readonly size: {
|
|
95
|
+
readonly type: import("vue").PropType<import("element-plus").ButtonType<(new (...args: any[]) => string | number) | (() => string | number) | ((new (...args: any[]) => string | number) | (() => string | number))[], unknown, unknown>>;
|
|
96
|
+
readonly required: false;
|
|
97
|
+
readonly validator: (val: unknown) => boolean;
|
|
98
|
+
__epPropKey: true;
|
|
99
|
+
};
|
|
100
|
+
readonly color: {
|
|
101
|
+
readonly type: import("vue").PropType<string>;
|
|
102
|
+
readonly required: false;
|
|
103
|
+
readonly validator: (val: unknown) => boolean;
|
|
104
|
+
__epPropKey: true;
|
|
105
|
+
};
|
|
106
|
+
}, {
|
|
107
|
+
props: Readonly<import("@vue/shared").LooseRequired<Readonly<import("vue").ExtractPropTypes<{
|
|
108
|
+
readonly size: {
|
|
109
|
+
readonly type: import("vue").PropType<import("element-plus").ButtonType<(new (...args: any[]) => string | number) | (() => string | number) | ((new (...args: any[]) => string | number) | (() => string | number))[], unknown, unknown>>;
|
|
110
|
+
readonly required: false;
|
|
111
|
+
readonly validator: (val: unknown) => boolean;
|
|
112
|
+
__epPropKey: true;
|
|
113
|
+
};
|
|
114
|
+
readonly color: {
|
|
115
|
+
readonly type: import("vue").PropType<string>;
|
|
116
|
+
readonly required: false;
|
|
117
|
+
readonly validator: (val: unknown) => boolean;
|
|
118
|
+
__epPropKey: true;
|
|
119
|
+
};
|
|
120
|
+
}>> & {
|
|
121
|
+
[x: `on${string}`]: ((...args: any[]) => any) | ((...args: unknown[]) => any);
|
|
122
|
+
}>>;
|
|
123
|
+
ns: {
|
|
124
|
+
namespace: import("vue").ComputedRef<string>;
|
|
125
|
+
b: (blockSuffix?: string) => string;
|
|
126
|
+
e: (element?: string) => string;
|
|
127
|
+
m: (modifier?: string) => string;
|
|
128
|
+
be: (blockSuffix?: string, element?: string) => string;
|
|
129
|
+
em: (element?: string, modifier?: string) => string;
|
|
130
|
+
bm: (blockSuffix?: string, modifier?: string) => string;
|
|
131
|
+
bem: (blockSuffix?: string, element?: string, modifier?: string) => string;
|
|
132
|
+
is: {
|
|
133
|
+
(name: string, state: boolean): string;
|
|
134
|
+
(name: string): string;
|
|
135
|
+
};
|
|
136
|
+
cssVar: (object: Record<string, string>) => Record<string, string>;
|
|
137
|
+
cssVarName: (name: string) => string;
|
|
138
|
+
cssVarBlock: (object: Record<string, string>) => Record<string, string>;
|
|
139
|
+
cssVarBlockName: (name: string) => string;
|
|
140
|
+
};
|
|
141
|
+
style: import("vue").ComputedRef<import("vue").CSSProperties>;
|
|
142
|
+
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
143
|
+
readonly size: {
|
|
144
|
+
readonly type: import("vue").PropType<import("element-plus").ButtonType<(new (...args: any[]) => string | number) | (() => string | number) | ((new (...args: any[]) => string | number) | (() => string | number))[], unknown, unknown>>;
|
|
145
|
+
readonly required: false;
|
|
146
|
+
readonly validator: (val: unknown) => boolean;
|
|
147
|
+
__epPropKey: true;
|
|
148
|
+
};
|
|
149
|
+
readonly color: {
|
|
150
|
+
readonly type: import("vue").PropType<string>;
|
|
151
|
+
readonly required: false;
|
|
152
|
+
readonly validator: (val: unknown) => boolean;
|
|
153
|
+
__epPropKey: true;
|
|
154
|
+
};
|
|
155
|
+
}>>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>> & Record<string, any>;
|
|
156
|
+
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
157
|
+
error: (evt: Event) => boolean;
|
|
158
|
+
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
159
|
+
readonly size: import("element-plus/es/utils").EpPropFinalized<readonly [NumberConstructor, StringConstructor], "" | "default" | "small" | "large", number, "", boolean>;
|
|
160
|
+
readonly shape: import("element-plus/es/utils").EpPropFinalized<StringConstructor, "circle" | "square", unknown, "circle", boolean>;
|
|
161
|
+
readonly icon: {
|
|
162
|
+
readonly type: import("vue").PropType<unknown>;
|
|
163
|
+
readonly required: false;
|
|
164
|
+
readonly validator: (val: unknown) => boolean;
|
|
165
|
+
__epPropKey: true;
|
|
166
|
+
};
|
|
167
|
+
readonly src: import("element-plus/es/utils").EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
|
|
168
|
+
readonly alt: StringConstructor;
|
|
169
|
+
readonly srcSet: StringConstructor;
|
|
170
|
+
readonly fit: import("element-plus/es/utils").EpPropFinalized<(new (...args: any[]) => any) | (() => any) | ((new (...args: any[]) => any) | (() => any))[], unknown, unknown, "cover", boolean>;
|
|
171
|
+
}>> & {
|
|
172
|
+
onError?: (evt: Event) => any;
|
|
173
|
+
}, {
|
|
174
|
+
readonly size: import("element-plus").ButtonType<readonly [NumberConstructor, StringConstructor], "" | "default" | "small" | "large", number>;
|
|
175
|
+
readonly shape: import("element-plus").ButtonType<StringConstructor, "circle" | "square", unknown>;
|
|
176
|
+
readonly src: string;
|
|
177
|
+
readonly fit: any;
|
|
178
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>> & Record<string, any>;
|
|
179
|
+
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
180
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
.sk-recorder-container {
|
|
2
|
+
position: relative;
|
|
3
|
+
}
|
|
4
|
+
.sk-recorder-button {
|
|
5
|
+
position: relative;
|
|
6
|
+
width: 100%;
|
|
7
|
+
touch-action: none;
|
|
8
|
+
user-select: none;
|
|
9
|
+
}
|
|
10
|
+
.recording-mask {
|
|
11
|
+
position: fixed;
|
|
12
|
+
top: 0;
|
|
13
|
+
left: 0;
|
|
14
|
+
right: 0;
|
|
15
|
+
bottom: 0;
|
|
16
|
+
background: rgba(0, 0, 0, 0.6);
|
|
17
|
+
z-index: 1000;
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
justify-content: space-between;
|
|
21
|
+
pointer-events: none;
|
|
22
|
+
}
|
|
23
|
+
.action-buttons {
|
|
24
|
+
pointer-events: auto;
|
|
25
|
+
display: flex;
|
|
26
|
+
justify-content: space-between;
|
|
27
|
+
padding: 20px 40px;
|
|
28
|
+
margin-bottom: 100px;
|
|
29
|
+
}
|
|
30
|
+
.cancel-btn, .text-btn {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
align-items: center;
|
|
34
|
+
color: white;
|
|
35
|
+
}
|
|
36
|
+
.btn-icon {
|
|
37
|
+
width: 60px; /* 增大按钮尺寸 */
|
|
38
|
+
height: 60px;
|
|
39
|
+
background: rgba(0, 0, 0, 0.4);
|
|
40
|
+
border-radius: 50%;
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
font-size: 28px;
|
|
45
|
+
margin-bottom: 8px;
|
|
46
|
+
}
|
|
47
|
+
.cancel-btn.active .btn-icon {
|
|
48
|
+
background: var(--el-color-danger);
|
|
49
|
+
}
|
|
50
|
+
.text-btn.active .btn-icon {
|
|
51
|
+
background: var(--el-color-primary);
|
|
52
|
+
}
|
|
53
|
+
.btn-text {
|
|
54
|
+
font-size: 14px;
|
|
55
|
+
}
|
|
56
|
+
.recording-tip {
|
|
57
|
+
flex: 1;
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
padding-bottom: 100px; /* 向上移动一些 */
|
|
63
|
+
color: white;
|
|
64
|
+
}
|
|
65
|
+
.wave-container {
|
|
66
|
+
width: 160px; /* 增大波形显示区域 */
|
|
67
|
+
height: 100px;
|
|
68
|
+
margin-bottom: 20px;
|
|
69
|
+
}
|
|
70
|
+
.tip-text {
|
|
71
|
+
font-size: 14px;
|
|
72
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { ElButton, ElMessage } from 'element-plus';
|
|
2
|
+
import Recorder from 'recorder-core';
|
|
3
|
+
import { defineComponent, ref, shallowRef, onUnmounted, resolveComponent, openBlock, createElementBlock, createCommentVNode, createElementVNode, toDisplayString, normalizeClass, createVNode, mergeProps, withCtx } from 'vue';
|
|
4
|
+
import 'recorder-core/src/engine/mp3';
|
|
5
|
+
import 'recorder-core/src/engine/wav';
|
|
6
|
+
import 'recorder-core/src/engine/mp3-engine';
|
|
7
|
+
import 'recorder-core/src/extensions/waveview';
|
|
8
|
+
import 'recorder-core/src/app-support/app';
|
|
9
|
+
import { _ as _export_sfc } from '../_plugin-vue_export-helper.mjs';
|
|
10
|
+
|
|
11
|
+
const props = {
|
|
12
|
+
speenchToTextUrl: {
|
|
13
|
+
type: String,
|
|
14
|
+
default: "http://localhost:3000/speech-to-text"
|
|
15
|
+
},
|
|
16
|
+
/**
|
|
17
|
+
* 自定义转为文本区域事件
|
|
18
|
+
*/
|
|
19
|
+
onTextZone: {
|
|
20
|
+
type: Function,
|
|
21
|
+
default: void 0
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const emits = {
|
|
25
|
+
submitText: (text) => typeof text === "string",
|
|
26
|
+
submit: (_) => true
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
async function speechToText(url, blob) {
|
|
30
|
+
const formData = new FormData();
|
|
31
|
+
formData.append("file", blob, "audio.wav");
|
|
32
|
+
const response = await fetch(url, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
body: formData
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
throw new Error("Speech to text failed");
|
|
38
|
+
}
|
|
39
|
+
const result = await response.json();
|
|
40
|
+
return result.text;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const LONG_PRESS_DURATION = 100;
|
|
44
|
+
var _sfc_main = defineComponent({
|
|
45
|
+
name: "VkRecorderButton",
|
|
46
|
+
components: {
|
|
47
|
+
ElButton
|
|
48
|
+
},
|
|
49
|
+
props,
|
|
50
|
+
emits,
|
|
51
|
+
setup(props2, { emit }) {
|
|
52
|
+
const supported = ref(false);
|
|
53
|
+
const recording = ref(false);
|
|
54
|
+
const recordingNode = ref();
|
|
55
|
+
const wave = shallowRef();
|
|
56
|
+
const blobUrl = ref("");
|
|
57
|
+
let pressTimer = null;
|
|
58
|
+
const rec = new Recorder({
|
|
59
|
+
// mp3格式,指定采样率hz、比特率kbps
|
|
60
|
+
type: "wav",
|
|
61
|
+
sampleRate: 16e3,
|
|
62
|
+
bitRate: 16,
|
|
63
|
+
onProcess
|
|
64
|
+
});
|
|
65
|
+
const recOpen = () => {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
rec.open(() => {
|
|
68
|
+
supported.value = true;
|
|
69
|
+
if (Recorder.WaveView) {
|
|
70
|
+
wave.value = Recorder.WaveView({
|
|
71
|
+
elem: recordingNode.value
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
resolve(true);
|
|
75
|
+
}, (msg, isUserNotAllow) => {
|
|
76
|
+
ElMessage.error(`${isUserNotAllow ? "\u7528\u6237\u672A\u6388\u6743, " : ""}\u65E0\u6CD5\u5F55\u97F3:${msg}`);
|
|
77
|
+
reject(new Error(msg));
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
const startRecording = async () => {
|
|
82
|
+
await recOpen();
|
|
83
|
+
if (!supported.value)
|
|
84
|
+
return;
|
|
85
|
+
rec.start();
|
|
86
|
+
recording.value = true;
|
|
87
|
+
};
|
|
88
|
+
const isDragging = ref(false);
|
|
89
|
+
const dragPosition = ref({ x: 0, y: 0 });
|
|
90
|
+
const cancelZone = ref(false);
|
|
91
|
+
const isTextZone = ref(false);
|
|
92
|
+
let isMouseDown = false;
|
|
93
|
+
const stopRecording = () => {
|
|
94
|
+
const theTextZone = isTextZone.value;
|
|
95
|
+
rec.stop(async (blob) => {
|
|
96
|
+
blobUrl.value = (window.URL || webkitURL).createObjectURL(blob);
|
|
97
|
+
rec.close();
|
|
98
|
+
recording.value = false;
|
|
99
|
+
emit("submit", {
|
|
100
|
+
blob,
|
|
101
|
+
url: blobUrl.value
|
|
102
|
+
});
|
|
103
|
+
if (theTextZone) {
|
|
104
|
+
if (props2.onTextZone) {
|
|
105
|
+
props2.onTextZone({
|
|
106
|
+
blob,
|
|
107
|
+
url: blobUrl.value
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
speechToText(props2.speenchToTextUrl, blob).then((text) => {
|
|
111
|
+
emit("submitText", text);
|
|
112
|
+
}).catch((err) => {
|
|
113
|
+
console.error("\u8BED\u97F3\u8BC6\u522B\u9519\u8BEF:", err);
|
|
114
|
+
ElMessage.error("\u8F6C\u6362\u6587\u5B57\u5931\u8D25");
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
const addDocumentListeners = () => {
|
|
121
|
+
document.addEventListener("mousemove", onmousemove);
|
|
122
|
+
document.addEventListener("mouseup", onmouseup);
|
|
123
|
+
};
|
|
124
|
+
const removeDocumentListeners = () => {
|
|
125
|
+
document.removeEventListener("mousemove", onmousemove);
|
|
126
|
+
document.removeEventListener("mouseup", onmouseup);
|
|
127
|
+
};
|
|
128
|
+
const onmousedown = (e) => {
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
isMouseDown = true;
|
|
131
|
+
const touch = "touches" in e ? e.touches[0] : e;
|
|
132
|
+
dragPosition.value = { x: touch.clientX, y: touch.clientY };
|
|
133
|
+
if (e instanceof MouseEvent) {
|
|
134
|
+
addDocumentListeners();
|
|
135
|
+
}
|
|
136
|
+
pressTimer = setTimeout(() => {
|
|
137
|
+
if (isMouseDown) {
|
|
138
|
+
isDragging.value = true;
|
|
139
|
+
startRecording();
|
|
140
|
+
}
|
|
141
|
+
}, LONG_PRESS_DURATION);
|
|
142
|
+
};
|
|
143
|
+
function onmousemove(e) {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
if (!isDragging.value)
|
|
146
|
+
return;
|
|
147
|
+
const touch = "touches" in e ? e.touches[0] : e;
|
|
148
|
+
dragPosition.value = { x: touch.clientX, y: touch.clientY };
|
|
149
|
+
const cancelBtn = document.querySelector(".cancel-btn");
|
|
150
|
+
const textBtn = document.querySelector(".text-btn");
|
|
151
|
+
if (cancelBtn && textBtn) {
|
|
152
|
+
const cancelRect = cancelBtn.getBoundingClientRect();
|
|
153
|
+
const textRect = textBtn.getBoundingClientRect();
|
|
154
|
+
cancelZone.value = touch.clientX >= cancelRect.left && touch.clientX <= cancelRect.right && touch.clientY >= cancelRect.top && touch.clientY <= cancelRect.bottom;
|
|
155
|
+
isTextZone.value = touch.clientX >= textRect.left && touch.clientX <= textRect.right && touch.clientY >= textRect.top && touch.clientY <= textRect.bottom;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function onmouseup(e) {
|
|
159
|
+
isMouseDown = false;
|
|
160
|
+
clearTimeout(pressTimer);
|
|
161
|
+
if (isDragging.value) {
|
|
162
|
+
if (cancelZone.value) {
|
|
163
|
+
rec.close();
|
|
164
|
+
} else {
|
|
165
|
+
stopRecording();
|
|
166
|
+
}
|
|
167
|
+
isDragging.value = false;
|
|
168
|
+
cancelZone.value = false;
|
|
169
|
+
isTextZone.value = false;
|
|
170
|
+
}
|
|
171
|
+
if (e instanceof MouseEvent) {
|
|
172
|
+
removeDocumentListeners();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function onProcess(buffers, powerLevel, bufferDuration, bufferSampleRate) {
|
|
176
|
+
wave.value?.input(
|
|
177
|
+
buffers[buffers.length - 1],
|
|
178
|
+
powerLevel,
|
|
179
|
+
bufferSampleRate
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
onUnmounted(() => {
|
|
183
|
+
removeDocumentListeners();
|
|
184
|
+
});
|
|
185
|
+
return {
|
|
186
|
+
onmousedown,
|
|
187
|
+
onmousemove,
|
|
188
|
+
onmouseup,
|
|
189
|
+
recording,
|
|
190
|
+
recordingNode,
|
|
191
|
+
blobUrl,
|
|
192
|
+
isDragging,
|
|
193
|
+
cancelZone,
|
|
194
|
+
isTextZone
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const _hoisted_1 = { class: "sk-recorder-container" };
|
|
200
|
+
const _hoisted_2 = {
|
|
201
|
+
key: 0,
|
|
202
|
+
class: "recording-mask"
|
|
203
|
+
};
|
|
204
|
+
const _hoisted_3 = { class: "recording-tip" };
|
|
205
|
+
const _hoisted_4 = {
|
|
206
|
+
ref: "recordingNode",
|
|
207
|
+
class: "wave-container"
|
|
208
|
+
};
|
|
209
|
+
const _hoisted_5 = { class: "tip-text" };
|
|
210
|
+
const _hoisted_6 = { class: "action-buttons" };
|
|
211
|
+
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
212
|
+
const _component_ElButton = resolveComponent("ElButton");
|
|
213
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
214
|
+
createCommentVNode(" \u906E\u7F69\u5C42 "),
|
|
215
|
+
_ctx.isDragging ? (openBlock(), createElementBlock("div", _hoisted_2, [
|
|
216
|
+
createCommentVNode(" \u5F55\u97F3\u63D0\u793A\u533A\u57DF\u79FB\u5230\u4E0A\u9762 "),
|
|
217
|
+
createElementVNode("div", _hoisted_3, [
|
|
218
|
+
createElementVNode(
|
|
219
|
+
"div",
|
|
220
|
+
_hoisted_4,
|
|
221
|
+
null,
|
|
222
|
+
512
|
|
223
|
+
/* NEED_PATCH */
|
|
224
|
+
),
|
|
225
|
+
createElementVNode(
|
|
226
|
+
"div",
|
|
227
|
+
_hoisted_5,
|
|
228
|
+
toDisplayString(_ctx.cancelZone ? "\u677E\u5F00\u624B\u6307\uFF0C\u53D6\u6D88\u53D1\u9001" : "\u677E\u5F00\u53D1\u9001\uFF0C\u4E0A\u6ED1\u53D6\u6D88"),
|
|
229
|
+
1
|
|
230
|
+
/* TEXT */
|
|
231
|
+
)
|
|
232
|
+
]),
|
|
233
|
+
createCommentVNode(" \u64CD\u4F5C\u6309\u94AE\u79FB\u5230\u5E95\u90E8 "),
|
|
234
|
+
createElementVNode("div", _hoisted_6, [
|
|
235
|
+
createElementVNode(
|
|
236
|
+
"div",
|
|
237
|
+
{
|
|
238
|
+
class: normalizeClass(["cancel-btn", { active: _ctx.cancelZone }])
|
|
239
|
+
},
|
|
240
|
+
_cache[0] || (_cache[0] = [
|
|
241
|
+
createElementVNode(
|
|
242
|
+
"div",
|
|
243
|
+
{ class: "btn-icon" },
|
|
244
|
+
" \xD7 ",
|
|
245
|
+
-1
|
|
246
|
+
/* HOISTED */
|
|
247
|
+
),
|
|
248
|
+
createElementVNode(
|
|
249
|
+
"div",
|
|
250
|
+
{ class: "btn-text" },
|
|
251
|
+
" \u53D6\u6D88\u53D1\u9001 ",
|
|
252
|
+
-1
|
|
253
|
+
/* HOISTED */
|
|
254
|
+
)
|
|
255
|
+
]),
|
|
256
|
+
2
|
|
257
|
+
/* CLASS */
|
|
258
|
+
),
|
|
259
|
+
createElementVNode(
|
|
260
|
+
"div",
|
|
261
|
+
{
|
|
262
|
+
class: normalizeClass(["text-btn", { active: _ctx.isTextZone }])
|
|
263
|
+
},
|
|
264
|
+
_cache[1] || (_cache[1] = [
|
|
265
|
+
createElementVNode(
|
|
266
|
+
"div",
|
|
267
|
+
{ class: "btn-icon" },
|
|
268
|
+
" \u6587 ",
|
|
269
|
+
-1
|
|
270
|
+
/* HOISTED */
|
|
271
|
+
),
|
|
272
|
+
createElementVNode(
|
|
273
|
+
"div",
|
|
274
|
+
{ class: "btn-text" },
|
|
275
|
+
" \u8F6C\u4E3A\u6587\u5B57 ",
|
|
276
|
+
-1
|
|
277
|
+
/* HOISTED */
|
|
278
|
+
)
|
|
279
|
+
]),
|
|
280
|
+
2
|
|
281
|
+
/* CLASS */
|
|
282
|
+
)
|
|
283
|
+
])
|
|
284
|
+
])) : createCommentVNode("v-if", true),
|
|
285
|
+
createCommentVNode(" \u5F55\u97F3\u6309\u94AE "),
|
|
286
|
+
createVNode(_component_ElButton, mergeProps(_ctx.$attrs, {
|
|
287
|
+
class: ["sk-recorder-button", {
|
|
288
|
+
"is-recording": _ctx.recording
|
|
289
|
+
}],
|
|
290
|
+
onTouchstart: _ctx.onmousedown,
|
|
291
|
+
onTouchmove: _ctx.onmousemove,
|
|
292
|
+
onTouchend: _ctx.onmouseup,
|
|
293
|
+
onMousedown: _ctx.onmousedown
|
|
294
|
+
}), {
|
|
295
|
+
default: withCtx(() => _cache[2] || (_cache[2] = [
|
|
296
|
+
createElementVNode(
|
|
297
|
+
"span",
|
|
298
|
+
{ class: "sk-recorder-button-text" },
|
|
299
|
+
"\u6309\u4F4F \u8BF4\u8BDD",
|
|
300
|
+
-1
|
|
301
|
+
/* HOISTED */
|
|
302
|
+
)
|
|
303
|
+
])),
|
|
304
|
+
_: 1
|
|
305
|
+
/* STABLE */
|
|
306
|
+
}, 16, ["class", "onTouchstart", "onTouchmove", "onTouchend", "onMousedown"])
|
|
307
|
+
]);
|
|
308
|
+
}
|
|
309
|
+
var VkRecorderButton = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__file", "/home/runner/work/vunk-plus/vunk-plus/packages/components/recorder-button/src/index.vue"]]);
|
|
310
|
+
|
|
311
|
+
var types = /*#__PURE__*/Object.freeze({
|
|
312
|
+
__proto__: null
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
VkRecorderButton.install = (app) => {
|
|
316
|
+
app.component(VkRecorderButton.name || "VkRecorderButton", VkRecorderButton);
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
export { VkRecorderButton, types as __VkRecorderButton, VkRecorderButton as default };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { PropType } from 'vue';
|
|
2
|
+
import type { OnTextZone, SubmitRawEvent } from './types';
|
|
3
|
+
export declare const props: {
|
|
4
|
+
speenchToTextUrl: {
|
|
5
|
+
type: StringConstructor;
|
|
6
|
+
default: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* 自定义转为文本区域事件
|
|
10
|
+
*/
|
|
11
|
+
onTextZone: {
|
|
12
|
+
type: PropType<OnTextZone>;
|
|
13
|
+
default: any;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare const emits: {
|
|
17
|
+
submitText: (text: string) => boolean;
|
|
18
|
+
submit: (_: SubmitRawEvent) => boolean;
|
|
19
|
+
};
|