@aochuang/client-sdk 1.0.355 → 1.0.358

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.
@@ -0,0 +1,99 @@
1
+ <template>
2
+ <div class="sdk-chat-wework-control-text" :class="['sdk-chat-wework-control-text--' + type]">
3
+ <div class="sdk-chat-wework-control-text__main">
4
+ <template v-if="hasScroll">
5
+ <ui-popover :value="showPopover" @input="handleShowPopoverChange">
6
+ <template slot="reference">
7
+ <div class="sdk-chat-wework-control-text__content" v-html="html" ref="popoverContent"></div>
8
+ </template>
9
+ <div class="sdk-chat-wework-control-text__popover" v-html="html" :style="{'width': popoverWidth}"></div>
10
+ </ui-popover>
11
+ </template>
12
+ <template v-else>
13
+ <div class="sdk-chat-wework-control-text__content" v-html="html" ref="content"></div>
14
+ </template>
15
+ </div>
16
+ </div>
17
+ </template>
18
+ <script>
19
+ import {Popover as UiPopover} from '@aochuang/common/components'
20
+ import {parseWechatEmoji} from '@aochuang/common/common/wechat-emoji'
21
+ import {html2Escape} from '../../../utils/string'
22
+
23
+ function parseTextContent (content) {
24
+ if (typeof content !== 'string') return content
25
+ try {
26
+ const data = JSON.parse(content)
27
+ return data && typeof data === 'object' ? data : content
28
+ } catch (e) {
29
+ return content
30
+ }
31
+ }
32
+
33
+ export default {
34
+ name: 'SdkChatControlTextDefault',
35
+ components: {UiPopover},
36
+ props: {
37
+ id: {type: String},
38
+ content: {type: [String, Object]},
39
+ type: {
40
+ type: String,
41
+ default: 'default',
42
+ validator (value) { return ['quote', 'default', 'thumb'].includes(value) }
43
+ },
44
+ formatter: {type: Function}
45
+ },
46
+ data () {
47
+ return {hasScroll: false, showPopover: false, popoverWidth: null}
48
+ },
49
+ computed: {
50
+ nextContent () { return parseTextContent(this.content) },
51
+ text () {
52
+ return this.nextContent && typeof this.nextContent === 'object' ? this.nextContent.text || '' : this.nextContent
53
+ },
54
+ html () {
55
+ let content = this.formatter ? this.formatter({content: this.nextContent}) : parseWechatEmoji(html2Escape(String(this.text || '')), false)
56
+ if (!content) return ''
57
+ content = String(content).replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, item => `<a href="${item}" target='_blank'>${item}</a>`)
58
+ return content.trim()
59
+ }
60
+ },
61
+ mounted () {
62
+ if (this.$refs.content) this.hasScroll = this.$refs.content.scrollHeight > this.$refs.content.clientHeight
63
+ },
64
+ methods: {
65
+ handleShowPopoverChange (visible) {
66
+ if (this.$refs.popoverContent && visible) this.popoverWidth = this.$refs.popoverContent.offsetWidth + 'px'
67
+ this.$nextTick(() => { this.showPopover = visible })
68
+ }
69
+ }
70
+ }
71
+ </script>
72
+ <style lang="less">
73
+ .sdk-chat-wework-control-text--default .sdk-chat-wework-control-text__main { padding: 10px; }
74
+ .sdk-chat-wework-control-text--quote .sdk-chat-wework-control-text__content {
75
+ display: -webkit-box;
76
+ -webkit-box-orient: vertical;
77
+ -webkit-line-clamp: 2;
78
+ overflow: hidden;
79
+ max-width: 420px;
80
+ }
81
+ .sdk-chat-wework-control-text--thumb {
82
+ background-color: #fff;
83
+ border: 1px solid #eee;
84
+ border-radius: 3px;
85
+ padding: 6px 10px;
86
+ }
87
+ .sdk-chat-wework-control-text--thumb .sdk-chat-wework-control-text__content {
88
+ display: -webkit-box;
89
+ -webkit-box-orient: vertical;
90
+ -webkit-line-clamp: 3;
91
+ overflow: hidden;
92
+ }
93
+ .sdk-chat-wework-control-text__main { white-space: pre-wrap; line-height: 1.5em; word-break: break-all; }
94
+ .sdk-chat-wework-control-text__main img { vertical-align: top; }
95
+ .sdk-chat-wework-control-text__main a { color: #4387ff; }
96
+ .sdk-chat-wework-control-text__main a:hover { color: #4387ff; text-decoration: underline; }
97
+ .sdk-chat-wework-control-text__popover { white-space: pre-wrap; line-height: 1.5em; word-break: break-all; padding: 10px; }
98
+ .sdk-chat-wework-control-text__popover img { vertical-align: top; }
99
+ </style>
@@ -0,0 +1,105 @@
1
+ <template>
2
+ <div class="sdk-chat-wework-control-text-quote" :class="['sdk-chat-wework-control-text-quote--' + type]">
3
+ <text-default :id="id" :content="mainContent" :type="type" :formatter="formatter"></text-default>
4
+ </div>
5
+ </template>
6
+ <script>
7
+ import {parse} from '../../../utils/json'
8
+ import {chatControls} from '../index'
9
+ import WeworkChatControlConfigMsg from '../wework-chat-control-config-msg.vue'
10
+ import TextDefault from './text-default.vue'
11
+
12
+ function parseQuoteContent (content) {
13
+ if (content && typeof content === 'object') return content
14
+ const parsed = parse(content, {})
15
+ if (!parsed || typeof parsed !== 'object' || !parsed.quote || typeof content !== 'string') return parsed
16
+ // JSON.parse converts large企微 message IDs to imprecise Numbers. Restore the
17
+ // original digit sequence before it is sent to the detail endpoint.
18
+ const match = content.match(/"messageId"\s*:\s*(?:"([^"]+)"|([0-9]+))/)
19
+ if (match) parsed.quote.messageId = match[1] || match[2]
20
+ return parsed
21
+ }
22
+
23
+ export default {
24
+ name: 'SdkChatControlTextQuote',
25
+ components: {TextDefault, WeworkChatControlConfigMsg},
26
+ props: {
27
+ id: {type: String},
28
+ content: {type: [String, Object]},
29
+ type: {type: String, default: 'default'},
30
+ formatter: {type: Function},
31
+ getQuoteMessage: {type: Function},
32
+ setChatBoxFootVnode: {type: Function}
33
+ },
34
+ data () { return {loading: false, quoteMessageData: null, errorMsg: null} },
35
+ computed: {
36
+ contentObject () {
37
+ return parseQuoteContent(this.content)
38
+ },
39
+ quoteInfo () { return this.contentObject.quote || {} },
40
+ mainContent () {
41
+ const value = Object.assign({}, this.contentObject)
42
+ delete value.quote
43
+ return JSON.stringify(value)
44
+ },
45
+ quoteText () { return this.quoteInfo.text || '引用消息' },
46
+ quoteAuthor () {
47
+ const message = this.quoteMessageData || {}
48
+ return this.quoteInfo.sendName || message.userName || message.contactName || message.roomName || this.quoteInfo.sendId || '引用消息'
49
+ },
50
+ quoteControl () {
51
+ return chatControls[this.quoteMessageData && this.quoteMessageData.msgType] || TextDefault
52
+ },
53
+ quoteFootComponent () {
54
+ return {
55
+ render: h => {
56
+ const content = [h('div', {class: 'sdk-chat-wework-control-text-quote__author'}, [this.quoteAuthor])]
57
+ if (this.loading) {
58
+ content.push(h('div', {class: 'sdk-chat-wework-control-text-quote__status'}, ['引用内容正在加载中...']))
59
+ } else if (this.quoteMessageData) {
60
+ content.push(h(WeworkChatControlConfigMsg, {
61
+ props: {msgData: this.quoteMessageData},
62
+ scopedSlots: {
63
+ default: ({configData}) => h(this.quoteControl, {
64
+ props: Object.assign({}, configData, {id: this.id + '_quote', content: this.quoteMessageData.content, type: 'quote'})
65
+ })
66
+ }
67
+ }))
68
+ } else {
69
+ content.push(h('div', {class: 'sdk-chat-wework-control-text-quote__content'}, [this.quoteText]))
70
+ if (this.errorMsg) content.push(h('div', {class: 'sdk-chat-wework-control-text-quote__status'}, [this.errorMsg]))
71
+ }
72
+ return h('div', {class: 'sdk-chat-wework-control-text-quote__box'}, content)
73
+ }
74
+ }
75
+ }
76
+ },
77
+ created () {
78
+ if (this.setChatBoxFootVnode) this.setChatBoxFootVnode(this.quoteFootComponent)
79
+ if (!this.getQuoteMessage || !this.quoteInfo.messageId || !this.quoteInfo.sendTime) {
80
+ this.errorMsg = '未找到引用消息内容,请在手机中确认'
81
+ return
82
+ }
83
+ this.loading = true
84
+ this.getQuoteMessage({
85
+ msgId: String(this.quoteInfo.messageId),
86
+ sendTime: this.quoteInfo.sendTime,
87
+ content: this.quoteInfo
88
+ }).then(data => {
89
+ this.quoteMessageData = data && data.data ? data.data : data
90
+ if (!this.quoteMessageData) this.errorMsg = '未找到引用消息内容,请在手机中确认'
91
+ if (this.setChatBoxFootVnode) this.setChatBoxFootVnode(this.quoteFootComponent)
92
+ }).catch(() => {
93
+ this.errorMsg = '未找到引用消息内容,请在手机中确认'
94
+ if (this.setChatBoxFootVnode) this.setChatBoxFootVnode(this.quoteFootComponent)
95
+ }).finally(() => { this.loading = false })
96
+ }
97
+ }
98
+ </script>
99
+ <style lang="less">
100
+ .sdk-chat-wework-control-text-quote { min-width: 0; }
101
+ .sdk-chat-wework-control-text-quote__box { margin: 10px 0 0; padding: 7px 8px; background: rgba(0, 0, 0, .06); border-radius: 3px; max-width: 420px; line-height: 1.5em; }
102
+ .sdk-chat-wework-control-text-quote__author { color: #999; word-break: break-all; }
103
+ .sdk-chat-wework-control-text-quote__content, .sdk-chat-wework-control-text-quote__status { white-space: pre-wrap; word-break: break-all; }
104
+ .sdk-chat-wework-control-text-quote__status { color: #999; font-size: 12px; }
105
+ </style>
@@ -1,177 +1,37 @@
1
1
  <template>
2
- <div
3
- class="sdk-chat-wework-control-text"
4
- :class="['sdk-chat-wework-control-text--' + type]"
5
- >
6
- <div class="sdk-chat-wework-control-text__main">
7
- <template v-if="hasScroll">
8
- <ui-popover
9
- :value="showPopover"
10
- @input="handleShowPopoverChange"
11
- >
12
- <template slot="reference">
13
- <div class="sdk-chat-wework-control-text__content"
14
- v-html="html"
15
- ref="popoverContent"
16
- ></div>
17
- </template>
18
- <div class="sdk-chat-wework-control-text__popover" v-html="html" :style="{'width': popoverWidth}"></div>
19
- </ui-popover>
20
- </template>
21
- <template v-else>
22
- <div class="sdk-chat-wework-control-text__content"
23
- v-html="html"
24
- ref="content"
25
- ></div>
26
- </template>
27
- </div>
28
- </div>
2
+ <component
3
+ :is="contentObject && contentObject.quote ? quoteComponent : defaultComponent"
4
+ v-bind="componentProps"
5
+ ></component>
29
6
  </template>
30
7
  <script>
31
- import { Popover as UiPopover } from '@aochuang/common/components'
32
- import { parseWechatEmoji } from '@aochuang/common/common/wechat-emoji'
33
- import { html2Escape } from '../../../utils/string'
8
+ import TextDefault from './text-default.vue'
9
+ import TextQuote from './text-quote.vue'
34
10
 
35
- function parseTextContent (content) {
36
- if (typeof content !== 'string') {
37
- return content
38
- }
39
- try {
40
- const data = JSON.parse(content)
41
- if (data && typeof data === 'object') {
42
- return data
43
- }
44
- } catch (e) {
45
- return content
46
- }
47
- return content
11
+ function parseContent (content) {
12
+ if (typeof content !== 'string') return content
13
+ try { return JSON.parse(content) } catch (e) { return content }
48
14
  }
49
15
 
50
16
  export default {
51
17
  name: 'SdkChatControlText',
52
- components: {
53
- UiPopover
54
- },
18
+ components: {TextDefault, TextQuote},
19
+ inheritAttrs: false,
55
20
  props: {
56
- id: {
57
- type: String
58
- },
59
- content: {
60
- type: String
61
- },
62
- type: {
63
- type: String,
64
- default: 'default',
65
- validator (value) {
66
- return ['quote', 'default', 'thumb'].includes(value)
67
- }
68
- },
69
- formatter: {
70
- type: Function
71
- }
72
- },
73
- data () {
74
- return {
75
- hasScroll: false,
76
- showPopover: false,
77
- popoverWidth: null
78
- }
21
+ id: {type: String},
22
+ content: {type: [String, Object]},
23
+ type: {type: String, default: 'default'},
24
+ formatter: {type: Function},
25
+ getQuoteMessage: {type: Function},
26
+ setChatBoxFootVnode: {type: Function}
79
27
  },
80
28
  computed: {
81
- nextContent () {
82
- return parseTextContent(this.content)
83
- },
84
- text () {
85
- if (this.nextContent && typeof this.nextContent === 'object') {
86
- return this.nextContent.text || ''
87
- }
88
- return this.nextContent
89
- },
90
- html () {
91
- let content = this.text
92
- if (this.formatter) {
93
- content = this.formatter({
94
- content: this.nextContent
95
- })
96
- } else {
97
- content = parseWechatEmoji(html2Escape(String(content || '')), false)
98
- }
99
- if (!content) {
100
- return ''
101
- }
102
- content = String(content)
103
- content = content.replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, item => {
104
- return `<a href="${item}" target='_blank'>${item}</a>`
105
- })
106
- return content.trim()
107
- }
108
- },
109
- mounted () {
110
- if (this.$refs.content) {
111
- this.hasScroll = this.$refs.content.scrollHeight > this.$refs.content.clientHeight
112
- }
113
- },
114
- methods: {
115
- handleShowPopoverChange (visible) {
116
- if (this.$refs.popoverContent && visible) {
117
- this.popoverWidth = this.$refs.popoverContent.offsetWidth + 'px'
118
- }
119
- this.$nextTick(() => {
120
- this.showPopover = visible
121
- })
29
+ contentObject () { return parseContent(this.content) },
30
+ defaultComponent () { return TextDefault },
31
+ quoteComponent () { return TextQuote },
32
+ componentProps () {
33
+ return Object.assign({}, this.$attrs, this.$props, {getQuoteMessage: this.getQuoteMessage})
122
34
  }
123
35
  }
124
36
  }
125
37
  </script>
126
- <style lang="less">
127
- .sdk-chat-wework-control-text--default {
128
- .sdk-chat-wework-control-text__main{
129
- padding: 10px;
130
- }
131
- }
132
- .sdk-chat-wework-control-text--quote {
133
- .sdk-chat-wework-control-text__content{
134
- display: -webkit-box;
135
- -webkit-box-orient: vertical;
136
- -webkit-line-clamp: 2; /* 限制显示3行 */
137
- overflow: hidden;
138
- max-width: 420px;
139
- }
140
- }
141
- .sdk-chat-wework-control-text--thumb {
142
- background-color: #fff;
143
- border: 1px solid #eee;
144
- border-radius: 3px;
145
- padding: 6px 10px;
146
- .sdk-chat-wework-control-text__content{
147
- display: -webkit-box;
148
- -webkit-box-orient: vertical;
149
- -webkit-line-clamp: 3; /* 限制显示3行 */
150
- overflow: hidden;
151
- }
152
- }
153
- .sdk-chat-wework-control-text__main{
154
- white-space: pre-wrap;
155
- line-height: 1.5em;
156
- word-break: break-all;
157
- img {
158
- vertical-align: top;
159
- }
160
- a {
161
- color: #4387ff;
162
- &:hover {
163
- color: #4387ff;
164
- text-decoration: underline;
165
- }
166
- }
167
- }
168
- .sdk-chat-wework-control-text__popover{
169
- white-space: pre-wrap;
170
- line-height: 1.5em;
171
- word-break: break-all;
172
- padding: 10px;
173
- img {
174
- vertical-align: top;
175
- }
176
- }
177
- </style>
@@ -20,10 +20,11 @@
20
20
  ref="player"
21
21
  :id="nextId"
22
22
  :url="voiceSrc"
23
+ :get-url-method="getUrlMethod"
23
24
  :enable-convert-to-wav="enableConvertToWav"
24
25
  :update-wav-method="updateWavMethod"
25
26
  :seconds="voiceDuration"
26
- :allow-download="allowDownload"
27
+ :allow-download="canDownload"
27
28
  ></ac-voice-player>
28
29
  </div>
29
30
  </div>
@@ -53,6 +54,7 @@
53
54
  import { parse } from '../../../utils/json'
54
55
  import { unique } from '../../../utils/string'
55
56
  import AcVoicePlayer from '@aochuang/common/common/voice-player'
57
+ import { formatOssPath } from '@aochuang/common/utils/oss'
56
58
 
57
59
  const ConvertStatusEnum = {
58
60
  NORMAL: -1, // 没有转换
@@ -100,6 +102,9 @@ export default {
100
102
  type: Boolean,
101
103
  default: true
102
104
  },
105
+ downloadMethod: {
106
+ type: Function
107
+ },
103
108
  transformVoiceToTextEnable: {
104
109
  type: Boolean,
105
110
  default: false
@@ -120,6 +125,7 @@ export default {
120
125
  },
121
126
  data () {
122
127
  return {
128
+ downloadedContent: null,
123
129
  transformStatus: typeof this.convertStatus === 'number' ? this.convertStatus : ConvertStatusEnum.NORMAL,
124
130
  playRate: 1,
125
131
  transforming: false,
@@ -129,11 +135,17 @@ export default {
129
135
  },
130
136
  computed: {
131
137
  nextContent () {
132
- return parse(this.content) || {}
138
+ return this.downloadedContent || parse(this.content) || {}
133
139
  },
134
140
  voiceSrc () {
135
- let url = this.nextContent.resPath
136
- return url
141
+ if (typeof this.nextContent === 'string') {
142
+ return this.nextContent
143
+ }
144
+ const voiceSrc = this.nextContent.resPath || this.nextContent.voicePath || this.nextContent.url || ''
145
+ if (!voiceSrc) {
146
+ return
147
+ }
148
+ return formatOssPath(voiceSrc)
137
149
  },
138
150
  nextId () {
139
151
  return this.id || unique()
@@ -141,6 +153,9 @@ export default {
141
153
  voiceDuration () {
142
154
  return this.nextContent.durationMs ? this.nextContent.durationMs : null
143
155
  },
156
+ canDownload () {
157
+ return this.allowDownload && !!this.nextContent.resPath
158
+ },
144
159
  isPlaying () {
145
160
  return this.AcVoice.isPlaying(this.id)
146
161
  },
@@ -169,6 +184,46 @@ export default {
169
184
  }
170
185
  },
171
186
  methods: {
187
+ getUrlMethod () {
188
+ const content = this.nextContent
189
+ const currentUrl = typeof content === 'string'
190
+ ? content
191
+ : content.resPath || content.url
192
+ if (currentUrl) {
193
+ return Promise.resolve(currentUrl)
194
+ }
195
+ if (!this.downloadMethod) {
196
+ return Promise.reject(new Error('未找到语音下载方法'))
197
+ }
198
+
199
+ const updateContentProps = (data) => {
200
+ if (!data || typeof data !== 'object' || Array.isArray(data)) {
201
+ throw new Error('updateContentProps只支持更新数据对象')
202
+ }
203
+ this.downloadedContent = data
204
+ return data
205
+ }
206
+ const result = this.downloadMethod({
207
+ content,
208
+ updateContentProp: (prop, value) => updateContentProps(Object.assign({}, this.nextContent, {[prop]: value})),
209
+ updateContentProps
210
+ })
211
+ return Promise.resolve(result).then((data) => {
212
+ const resultContent = typeof data === 'string' ? {url: data} : data
213
+ const url = resultContent && (resultContent.resPath || resultContent.url)
214
+ if (url) {
215
+ return url
216
+ }
217
+ const nextContent = this.nextContent
218
+ const nextUrl = typeof nextContent === 'string'
219
+ ? nextContent
220
+ : nextContent.resPath || nextContent.url
221
+ if (nextUrl) {
222
+ return nextUrl
223
+ }
224
+ throw new Error('语音下载未返回有效地址')
225
+ })
226
+ },
172
227
  handleTransformClick () {
173
228
  if (this.transformVoiceToTextMethod) {
174
229
  this.transforming = true
@@ -16,11 +16,14 @@
16
16
  @user-avatar-click="handleUserAvatarClick"
17
17
  @user-avatar-contextmenu="handleUserAvatarContextmenu"
18
18
  >
19
- <sdk-chat-control-text
20
- v-bind="configData"
21
- :id="item.id"
22
- :content="msgContent"
23
- ></sdk-chat-control-text>
19
+ <template slot-scope="{ setFootVnode }">
20
+ <sdk-chat-control-text
21
+ v-bind="configData"
22
+ :id="item.id"
23
+ :content="msgContent"
24
+ :set-chat-box-foot-vnode="setFootVnode"
25
+ ></sdk-chat-control-text>
26
+ </template>
24
27
  <template slot="append" slot-scope="{ updateProp }">
25
28
  <slot name="chat-append" :item="item" :update-chat-box-prop="updateProp"></slot>
26
29
  </template>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aochuang/client-sdk",
3
- "version": "1.0.355",
3
+ "version": "1.0.358",
4
4
  "description": "",
5
5
  "files": [
6
6
  "common",