im-ui-mobile 0.0.42 → 0.0.44

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 (42) hide show
  1. package/components/im-arrow-bar/im-arrow-bar.vue +59 -0
  2. package/components/im-bar-group/im-bar-group.vue +17 -0
  3. package/components/im-btn-bar/im-btn-bar.vue +60 -0
  4. package/components/im-chat-at-box/im-chat-at-box.vue +189 -0
  5. package/components/im-chat-group-readed/im-chat-group-readed.vue +172 -0
  6. package/components/im-chat-item/im-chat-item.vue +215 -0
  7. package/components/im-chat-message-item/im-chat-message-item.vue +559 -0
  8. package/components/im-chat-record/im-chat-record.vue +303 -0
  9. package/components/im-file-upload/im-file-upload.vue +300 -0
  10. package/components/im-friend-item/im-friend-item.vue +74 -0
  11. package/components/im-group-item/im-group-item.vue +60 -0
  12. package/components/im-group-member-selector/im-group-member-selector.vue +199 -0
  13. package/components/im-group-rtc-join/im-group-rtc-join.vue +112 -0
  14. package/components/im-head-image/im-head-image.vue +122 -0
  15. package/components/im-image-upload/im-image-upload.vue +90 -0
  16. package/components/im-loading/im-loading.vue +63 -0
  17. package/components/im-long-press-menu/im-long-press-menu.vue +137 -0
  18. package/components/im-nav-bar/im-nav-bar.vue +99 -0
  19. package/components/im-switch-bar/im-switch-bar.vue +60 -0
  20. package/components/im-virtual-scroller/im-virtual-scroller.vue +52 -0
  21. package/index.js +37 -27
  22. package/package.json +8 -2
  23. package/plugins/pinia.js +19 -0
  24. package/types/components/arrow-bar.d.ts +14 -0
  25. package/types/components/bar-group.d.ts +14 -0
  26. package/types/components/btn-bar.d.ts +16 -0
  27. package/types/components/chat-at-box.d.ts +22 -0
  28. package/types/components/chat-group-readed.d.ts +30 -0
  29. package/types/components/chat-item.d.ts +21 -0
  30. package/types/components/chat-message-item.d.ts +28 -0
  31. package/types/components/chat-record.d.ts +14 -0
  32. package/types/components/chat-upload.d.ts +58 -0
  33. package/types/components/friend-item.d.ts +19 -0
  34. package/types/components/group-item.d.ts +18 -0
  35. package/types/components/group-member-selector.d.ts +31 -0
  36. package/types/components/group-rtc-join.d.ts +31 -0
  37. package/types/components/head-image.d.ts +18 -0
  38. package/types/components/im-loading.d.ts +20 -0
  39. package/types/components/long-press-menu.d.ts +23 -0
  40. package/types/components/sample.d.ts +1 -3
  41. package/types/components/switch-bar.d.ts +19 -0
  42. package/types/components/virtual-scroller.d.ts +20 -0
@@ -0,0 +1,137 @@
1
+ <template>
2
+ <view class="long-press-menu none-pointer-events">
3
+ <view @longpress.prevent.stop="onLongPress($event)" @touchmove="onTouchMove" @touchend="onTouchEnd">
4
+ <slot></slot>
5
+ </view>
6
+ <view v-if="isShowMenu" class="menu-mask" @touchstart="onClose()" @contextmenu.prevent=""></view>
7
+ <view v-if="isShowMenu" class="menu" :style="menuStyle">
8
+ <view class="menu-item" v-for="(item) in items" :key="item.key" @click.prevent="onSelectMenu(item)">
9
+ <text :style="itemStyle(item)"> {{ item.name }}</text>
10
+ </view>
11
+ </view>
12
+ </view>
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ interface Props {
17
+ items?: any[];
18
+ }
19
+
20
+ interface Emits {
21
+ (e: 'select', item: any): void;
22
+ }
23
+
24
+ interface TouchPoint {
25
+ clientX: number;
26
+ clientY: number;
27
+ }
28
+
29
+ const props = defineProps<Props>();
30
+ const emit = defineEmits<Emits>();
31
+
32
+ const isShowMenu = ref(false);
33
+ const isTouchMove = ref(false);
34
+ const menuStyle = ref("");
35
+ const menuTouch = ref<TouchPoint>({ clientX: 0, clientY: 0 });
36
+
37
+ const onLongPress = (e: any) => {
38
+ if (isTouchMove.value) {
39
+ // 屏幕移动时不弹出
40
+ return;
41
+ }
42
+
43
+ uni.getSystemInfo({
44
+ success: (res) => {
45
+ const touches = e.touches[0];
46
+ let style = "";
47
+ /* 因 非H5端不兼容 style 属性绑定 Object ,所以拼接字符 */
48
+ if (touches.clientY > (res.windowHeight / 2)) {
49
+ style = `bottom:${res.windowHeight - touches.clientY + 20}px;`;
50
+ } else {
51
+ style = `top:${touches.clientY + 20}px;`;
52
+ }
53
+ if (touches.clientX > (res.windowWidth / 2)) {
54
+ style += `right:${res.windowWidth - touches.clientX}px;`;
55
+ } else {
56
+ style += `left:${touches.clientX}px;`;
57
+ }
58
+ menuStyle.value = style;
59
+
60
+ menuTouch.value = touches;
61
+ isShowMenu.value = true;
62
+ }
63
+ });
64
+ };
65
+
66
+ const onTouchMove = (e: any) => {
67
+ isTouchMove.value = true;
68
+ const touches = e.touches[0];
69
+ // 屏幕拖动大于50px时,取消菜单
70
+ if (Math.abs(touches.clientX - menuTouch.value.clientX) > 50 ||
71
+ Math.abs(touches.clientY - menuTouch.value.clientY) > 50) {
72
+ onClose();
73
+ }
74
+ };
75
+
76
+ const onTouchEnd = () => {
77
+ isTouchMove.value = false;
78
+ };
79
+
80
+ const onSelectMenu = (item: any) => {
81
+ emit("select", item);
82
+ isShowMenu.value = false;
83
+ };
84
+
85
+ const onClose = () => {
86
+ isShowMenu.value = false;
87
+ };
88
+
89
+ const itemStyle = (item: any) => {
90
+ if (item.color) {
91
+ return `color:${item.color};`;
92
+ }
93
+ return `color:#000;`;
94
+ };
95
+ </script>
96
+
97
+ <style lang="scss" scoped>
98
+ .long-press-menu {
99
+ .menu-mask {
100
+ position: fixed;
101
+ left: 0;
102
+ top: 0;
103
+ right: 0;
104
+ bottom: 0;
105
+ width: 100%;
106
+ height: 100%;
107
+ z-index: 999;
108
+ }
109
+
110
+ .menu {
111
+ position: fixed;
112
+ border-radius: 4px;
113
+ overflow: hidden;
114
+ background-color: #fff;
115
+ z-index: 1000;
116
+ box-shadow: $im-box-shadow-dark;
117
+
118
+ .menu-item {
119
+ height: 28px;
120
+ min-width: 120rpx;
121
+ line-height: 28px;
122
+ font-size: $im-font-size-small;
123
+ display: flex;
124
+ padding: 6px 20px;
125
+ justify-content: flex-start;
126
+
127
+ &:hover {
128
+ background: $im-bg-active;
129
+ }
130
+
131
+ .menu-icon {
132
+ margin-right: 10rpx;
133
+ }
134
+ }
135
+ }
136
+ }
137
+ </style>
@@ -0,0 +1,99 @@
1
+ <template>
2
+ <view class="nav-bar">
3
+ <!-- #ifdef APP-PLUS -->
4
+ <view style="height: var(--status-bar-height)"></view>
5
+ <!-- #endif -->
6
+ <view class="nav-bar-content">
7
+ <!-- #ifndef MP-WEIXIN -->
8
+ <view class="back" @click="handleBackClick" v-if="back">
9
+ <u-icon name="arrow-left" :size="iconFontSize"></u-icon>
10
+ </view>
11
+ <!-- #endif -->
12
+ <view class="title" v-if="title">
13
+ <slot></slot>
14
+ </view>
15
+ <view class="btn">
16
+ <u-icon class="btn-item" v-if="search" name="search" :size="iconFontSize"
17
+ @click="$emit('search')"></u-icon>
18
+ <u-icon class="btn-item" v-if="add" name="plus" :size="iconFontSize" @click="$emit('add')"></u-icon>
19
+ <u-icon class="btn-item" v-if="more" name="more-dot-fill" :size="iconFontSize"
20
+ @click="$emit('more')"></u-icon>
21
+ </view>
22
+ </view>
23
+ </view>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ interface Props {
28
+ back?: boolean;
29
+ title?: boolean;
30
+ search?: boolean;
31
+ add?: boolean;
32
+ more?: boolean;
33
+ iconFontSize?: number;
34
+ }
35
+
36
+ const props = withDefaults(defineProps<Props>(), {
37
+ back: false,
38
+ title: true,
39
+ search: false,
40
+ add: false,
41
+ more: false,
42
+ iconFontSize: 24
43
+ });
44
+
45
+ const handleBackClick = () => {
46
+ uni.navigateBack({
47
+ delta: 1
48
+ });
49
+ };
50
+ </script>
51
+
52
+ <style scoped lang="scss">
53
+ .nav-bar {
54
+ background: $im-bg-linear;
55
+ position: fixed;
56
+ top: 0;
57
+ width: 100%;
58
+ color: $im-text-color;
59
+ border-bottom: 1px solid $im-border-light;
60
+ font-size: $im-font-size-large;
61
+ z-index: 99;
62
+
63
+ .nav-bar-content {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ box-sizing: border-box;
68
+ height: $im-nav-bar-height;
69
+
70
+ .title {}
71
+
72
+ .back {
73
+ position: absolute;
74
+ left: 0;
75
+ height: 100%;
76
+ display: flex;
77
+ align-items: center;
78
+ padding: 12px;
79
+ font-size: 22px;
80
+ box-sizing: border-box;
81
+ }
82
+
83
+ .btn {
84
+ position: absolute;
85
+ right: 0;
86
+ height: 100%;
87
+ display: flex;
88
+ padding: 12px;
89
+ align-items: center;
90
+ box-sizing: border-box;
91
+
92
+ .btn-item {
93
+ margin-left: 8px;
94
+ }
95
+ }
96
+ }
97
+
98
+ }
99
+ </style>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <view class="switch-bar">
3
+ <text class="title">{{ title }}</text>
4
+ <switch class="switch" :checked="checked" color="#18bc37" @change="onChange"></switch>
5
+ </view>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ interface Props {
10
+ title: string;
11
+ checked?: boolean;
12
+ }
13
+
14
+ interface Emits {
15
+ (e: 'change', value: boolean): void;
16
+ }
17
+
18
+ const props = withDefaults(defineProps<Props>(), {
19
+ checked: false
20
+ });
21
+
22
+ const emit = defineEmits<Emits>();
23
+
24
+ const value = ref(props.checked);
25
+
26
+ watch(() => props.checked, (newVal) => {
27
+ value.value = newVal;
28
+ });
29
+
30
+ const onChange = (e: any) => {
31
+ value.value = true;
32
+ setTimeout(() => {
33
+ value.value = false;
34
+ }, 100);
35
+
36
+ emit('change', e);
37
+ };
38
+ </script>F
39
+
40
+ <style lang="scss" scoped>
41
+ .switch-bar {
42
+ width: 100%;
43
+ height: 100rpx;
44
+ font-size: 34rpx;
45
+ color: black;
46
+ margin-top: 5rpx;
47
+ background-color: white;
48
+ line-height: 100rpx;
49
+ display: flex;
50
+
51
+ .title {
52
+ flex: 1;
53
+ margin-left: 40rpx;
54
+ }
55
+
56
+ .switch {
57
+ margin-right: 40rpx;
58
+ }
59
+ }
60
+ </style>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <scroll-view scroll-y="true" :style="{ height: height }" upper-threshold="200" @scrolltolower="onScrollToBottom"
3
+ scroll-with-animation="true">
4
+ <view class="virtual-scroller" v-for="(item, idx) in showItems" :key="idx">
5
+ <slot :item="item">
6
+ </slot>
7
+ </view>
8
+ </scroll-view>
9
+ </template>
10
+
11
+ <script setup lang="ts">
12
+ interface Props {
13
+ height?: string;
14
+ items?: any[];
15
+ size?: number;
16
+ }
17
+
18
+ const props = withDefaults(defineProps<Props>(), {
19
+ height: '60vh',
20
+ items: () => [],
21
+ size: 30
22
+ });
23
+
24
+ const page = ref(1);
25
+ const isInitEvent = ref(false);
26
+ const lockTip = ref(false);
27
+
28
+ const onScrollToBottom = (e: any) => {
29
+ if (showMaxIdx.value >= props.items.length) {
30
+ showTip();
31
+ } else {
32
+ page.value++;
33
+ }
34
+ };
35
+
36
+ const showTip = () => {
37
+ uni.showToast({
38
+ title: "已滚动至底部",
39
+ icon: 'none'
40
+ });
41
+ };
42
+
43
+ const showMaxIdx = computed(() => {
44
+ return Math.min(page.value * props.size, props.items.length);
45
+ });
46
+
47
+ const showItems = computed(() => {
48
+ return props.items.slice(0, showMaxIdx.value);
49
+ });
50
+ </script>
51
+
52
+ <style scoped></style>
package/index.js CHANGED
@@ -1,43 +1,53 @@
1
+ import { Pinia } from './plugins/pinia.js'
1
2
  import { UViewPlusPlugin } from './plugins/uview-plus.js'
2
- import ImSample from './components/im-sample/im-sample.vue'
3
+ // import ImSample from './components/im-sample/im-sample.vue'
3
4
 
4
- // 重要:为组件添加名称,以支持开发环境
5
- ImSample.name = 'ImSample'
5
+ // // 重要:为组件添加名称,以支持开发环境
6
+ // ImSample.name = 'ImSample'
6
7
 
7
- const components = [
8
- ImSample
9
- ]
8
+ // const components = [
9
+ // ImSample
10
+ // ]
10
11
 
11
- // const importFn = import.meta.glob('./components/im-*/im-*.vue', { eager: true })
12
- // const components = [];
12
+ const importFn = import.meta.glob('./components/im-*/im-*.vue', { eager: true })
13
+ const components = [];
13
14
 
14
- // for (const key in importFn) {
15
- // const component = importFn[key].default;
16
-
17
- // // 1. 从文件路径中提取组件名(更可靠的方法)
18
- // const fileName = key.split('/').pop(); // 获取文件名,如 im-button.vue
19
- // const componentName = fileName
20
- // .replace('.vue', '') // 去掉 .vue 后缀
21
- // .replace(/\b\w/g, l => l.toUpperCase()) // 首字母大写,如 ImButton
22
-
23
- // // 2. 添加到组件列表
24
- // if (component) {
25
- // // 如果组件本身没有 name,给它设置一个
26
- // if (!component.name) {
27
- // component.name = componentName;
28
- // }
15
+ for (const key in importFn) {
16
+ const component = importFn[key].default;
29
17
 
30
- // components.push(component);
31
- // }
32
- // }
18
+ // 1. 从文件路径中提取组件名(更可靠的方法)
19
+ const fileName = key.split('/').pop(); // 获取文件名,如 im-button.vue
20
+ const componentName = fileName
21
+ .replace('.vue', '') // 去掉 .vue 后缀
22
+ .replace(/\b\w/g, l => l.toUpperCase()) // 首字母大写,如 ImButton
23
+
24
+ // 2. 添加到组件列表
25
+ if (component) {
26
+ // 如果组件本身没有 name,给它设置一个
27
+ if (!component.name) {
28
+ component.name = componentName;
29
+ }
30
+
31
+ components.push(component);
32
+ }
33
+ }
34
+
35
+ const install = (app, options = {}) => {
36
+ // 安装pinia插件
37
+ if (options.usePinia !== false) {
38
+ app.use(Pinia, options.piniaOptions)
39
+ }
33
40
 
34
- const install = (app) => {
35
41
  // 安装 uview-plus
36
42
  app.use(UViewPlusPlugin)
37
43
 
44
+ // 注册组件
38
45
  components.forEach(component => {
39
46
  app.component(component.name || '', component)
40
47
  })
48
+
49
+ // 提供全局配置
50
+ app.provide('im-config', options.config || {})
41
51
  }
42
52
 
43
53
  import eventBus from "./utils/eventBus.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "im-ui-mobile",
3
- "version": "0.0.42",
3
+ "version": "0.0.44",
4
4
  "description": "A Vue3.0 + typescript instant messaging component library for Uniapp",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -36,7 +36,13 @@
36
36
  "peerDependencies": {
37
37
  "@dcloudio/uni-app": "3.0.0-4070520250711001",
38
38
  "uview-plus": "^3.1.0",
39
- "vue": "^3.3.0"
39
+ "vue": "^3.3.0",
40
+ "pinia": "^2.1.7"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "pinia": {
44
+ "optional": true
45
+ }
40
46
  },
41
47
  "keywords": [
42
48
  "vue3",
@@ -0,0 +1,19 @@
1
+ import { createPinia } from 'pinia'
2
+
3
+ export const Pinia = {
4
+ install(app, options = {}) {
5
+ // 创建pinia实例
6
+ const pinia = createPinia()
7
+
8
+ // 可选:添加插件
9
+ if (options.persist) {
10
+ pinia.use(piniaPluginPersistedstate)
11
+ }
12
+
13
+ // 注册pinia
14
+ app.use(pinia)
15
+
16
+ // 提供injection key
17
+ app.provide('imPinia', pinia)
18
+ }
19
+ }
@@ -0,0 +1,14 @@
1
+ import { AllowedComponentProps, VNodeProps } from './_common'
2
+
3
+ declare interface ArrowBarProps {
4
+ title: string
5
+ icon?: string
6
+ }
7
+
8
+ declare interface _ArrowBar {
9
+ new(): {
10
+ $props: AllowedComponentProps & VNodeProps & ArrowBarProps
11
+ }
12
+ }
13
+
14
+ export declare const ArrowBar: _ArrowBar
@@ -0,0 +1,14 @@
1
+ import { AllowedComponentProps, VNodeProps } from './_common'
2
+
3
+ declare interface BarGroupSlots {
4
+ default?: () => any
5
+ }
6
+
7
+ declare interface _BarGroup {
8
+ new(): {
9
+ $props: AllowedComponentProps & VNodeProps
10
+ $slots: BarGroupSlots
11
+ }
12
+ }
13
+
14
+ export declare const BarGroup: _BarGroup
@@ -0,0 +1,16 @@
1
+ import { AllowedComponentProps, VNodeProps } from './_common'
2
+
3
+ declare interface BtnBarProps {
4
+ title: string
5
+ icon?: string
6
+ type?: 'normal' | 'danger' | 'primary'
7
+ color?: string
8
+ }
9
+
10
+ declare interface _BtnBar {
11
+ new(): {
12
+ $props: AllowedComponentProps & VNodeProps & BtnBarProps
13
+ }
14
+ }
15
+
16
+ export declare const BtnBar: _BtnBar
@@ -0,0 +1,22 @@
1
+ import { AllowedComponentProps, VNodeProps } from './_common'
2
+ import { GroupMember } from '../../libs'
3
+
4
+ declare interface ChatAtBoxProps {
5
+ ownerId?: number
6
+ members?: any[]
7
+ }
8
+
9
+ declare interface ChatAtBoxEmits {
10
+ (e: 'complete', userIds: number[]): void
11
+ }
12
+
13
+ declare interface _ChatAtBox {
14
+ new(): {
15
+ $props: AllowedComponentProps & VNodeProps & ChatAtBoxProps
16
+ $emit: ChatAtBoxEmits
17
+ }
18
+ init: (userId: number, atUserIds: number[]) => void
19
+ open: () => void
20
+ }
21
+
22
+ export declare const ChatAtBox: _ChatAtBox
@@ -0,0 +1,30 @@
1
+ import { AllowedComponentProps, VNodeProps } from './_common'
2
+ import { Chat, Message } from '../../libs'
3
+
4
+ declare interface ChatGroupReadedProps {
5
+ msgInfo: {
6
+ groupId: number
7
+ id: number
8
+ sendId: number
9
+ }
10
+ groupMembers: any[]
11
+ }
12
+
13
+ declare interface ChatGroupReadedEmits {
14
+ (e: 'loaded', chatInfo: Chat, msgInfo: Message): void
15
+ }
16
+
17
+ declare interface Member {
18
+ userId: number
19
+ quit?: boolean
20
+ }
21
+
22
+ declare interface _ChatGroupReaded {
23
+ new(): {
24
+ $props: AllowedComponentProps & VNodeProps & ChatGroupReadedProps
25
+ $emit: ChatGroupReadedEmits
26
+ }
27
+ open: (userIds: number[]) => void
28
+ }
29
+
30
+ export declare const ChatGroupReaded: _ChatGroupReaded
@@ -0,0 +1,21 @@
1
+ import { AllowedComponentProps, VNodeProps } from './_common'
2
+
3
+ declare interface ChatItemProps {
4
+ chat?: any
5
+ index?: number
6
+ active?: boolean
7
+ online: boolean
8
+ }
9
+
10
+ declare interface ChatItemEmits {
11
+ (e: 'click', targetId: number): void
12
+ }
13
+
14
+ declare interface _ChatItem {
15
+ new(): {
16
+ $props: AllowedComponentProps & VNodeProps & ChatItemProps
17
+ $emit: ChatItemEmits
18
+ }
19
+ }
20
+
21
+ export declare const ChatItem: _ChatItem
@@ -0,0 +1,28 @@
1
+ import { AllowedComponentProps, VNodeProps } from './_common'
2
+
3
+ declare interface ChatMessageItemProps {
4
+ avatar?: string
5
+ showName: string
6
+ msgInfo: any
7
+ groupMembers?: any[]
8
+ }
9
+
10
+ declare interface ChatMessageItemEmits {
11
+ (e: 'call'): void
12
+ (e: 'longPressHead'): void
13
+ (e: 'resend', msgInfo: any): void
14
+ (e: 'audioStateChange', state: string, msgInfo: any): void
15
+ (e: 'copy', msgInfo: any): void
16
+ (e: 'recall', msgInfo: any): void
17
+ (e: 'delete', msgInfo: any): void
18
+ (e: 'download', msgInfo: any): void
19
+ }
20
+
21
+ declare interface _ChatMessageItem {
22
+ new(): {
23
+ $props: AllowedComponentProps & VNodeProps & ChatMessageItemProps
24
+ $emit: ChatMessageItemEmits
25
+ }
26
+ }
27
+
28
+ export declare const ChatMessageItem: _ChatMessageItem
@@ -0,0 +1,14 @@
1
+ import { AllowedComponentProps, VNodeProps } from './_common'
2
+
3
+ declare interface ChatRecordEmits {
4
+ (e: 'send', data: any): void
5
+ }
6
+
7
+ declare interface _ChatRecord {
8
+ new(): {
9
+ $props: AllowedComponentProps & VNodeProps
10
+ $emit: ChatRecordEmits
11
+ }
12
+ }
13
+
14
+ export declare const ChatRecord: _ChatRecord