ai-chat-bot-interface 1.7.7 → 1.7.9

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 (55) hide show
  1. package/dist/assets/index-DQulfwi9.css +9 -0
  2. package/dist/assets/index-Dkddqe_3.js +123 -0
  3. package/{index.html → dist/index.html} +2 -1
  4. package/dist/src/index.d.ts +0 -0
  5. package/package.json +26 -5
  6. package/.prettierignore +0 -5
  7. package/.prettierrc.cjs +0 -37
  8. package/.vscode/extensions.json +0 -3
  9. package/index.js +0 -11
  10. package/src/App.vue +0 -39
  11. package/src/ChatUi.less +0 -301
  12. package/src/ChatUi.vue +0 -1087
  13. package/src/assets/styles/public.less +0 -152
  14. package/src/assets/vue.svg +0 -1
  15. package/src/components/DishesCard.vue +0 -369
  16. package/src/components/DishesList.vue +0 -207
  17. package/src/components/MarkdownPlan/MarkdownViewer.vue +0 -34
  18. package/src/components/OperateModule.less +0 -186
  19. package/src/components/OperateModule.vue +0 -392
  20. package/src/components/PlanCard.vue +0 -114
  21. package/src/components/StoreList/StoreCard.vue +0 -72
  22. package/src/components/StoreList/StoreList.vue +0 -27
  23. package/src/components/StoreList/mock.js +0 -411
  24. package/src/components/assistantReplay/assistantReplay.vue +0 -78
  25. package/src/components/icons/ArrowDown.vue +0 -26
  26. package/src/components/icons/ArrowRight.vue +0 -19
  27. package/src/components/icons/BackIcon.vue +0 -19
  28. package/src/components/icons/ClearIcon.vue +0 -18
  29. package/src/components/icons/CloseIcon.vue +0 -17
  30. package/src/components/icons/NewSessionIcon.vue +0 -20
  31. package/src/components/icons/OkIcon.vue +0 -26
  32. package/src/components/icons/SendIcon.vue +0 -22
  33. package/src/components/icons/ThinkingIcon.vue +0 -28
  34. package/src/components/icons/addIcon.vue +0 -18
  35. package/src/components/icons/cameraIcon.vue +0 -22
  36. package/src/components/icons/closeBorderIcon.vue +0 -35
  37. package/src/components/icons/fileIcon.vue +0 -18
  38. package/src/components/icons/loadingIcon.vue +0 -76
  39. package/src/components/icons/loadingIcon2.vue +0 -88
  40. package/src/components/icons/newChat.vue +0 -18
  41. package/src/components/icons/pictureIcon.vue +0 -22
  42. package/src/components/icons/processBar.vue +0 -115
  43. package/src/components/icons/progressRing.vue +0 -63
  44. package/src/components/icons/sendLoadingIcon.vue +0 -35
  45. package/src/components/icons/tagIcon.vue +0 -18
  46. package/src/components/imgeList.vue +0 -63
  47. package/src/components/personalForm/personalForm.vue +0 -634
  48. package/src/components/popup/popup.vue +0 -178
  49. package/src/main.js +0 -26
  50. package/src/style.css +0 -4
  51. package/src/utils/imagesViewer.js +0 -8
  52. package/src/utils/request.js +0 -52
  53. package/src/utils/tools.js +0 -20
  54. package/vite.config.js +0 -33
  55. /package/{public → dist}/vite.svg +0 -0
@@ -1,392 +0,0 @@
1
- <template>
2
- <div class="om_wrap">
3
- <div class="om_quick">
4
- <div
5
- class="tag"
6
- v-for="item in tagList"
7
- :key="item.value"
8
- @click.stop="handleTag(item)"
9
- >
10
- <tag-icon class="icon" />
11
- {{ item.name }}
12
- </div>
13
- </div>
14
- <div class="om_operate_box">
15
- <div v-if="newChat" class="new_chat" @click.stop="newChatFunc">
16
- <new-chat />
17
- </div>
18
- <div class="om_operate_wrap">
19
- <div class="file_list_box" :class="{ hidden: !uploadPlane }">
20
- <div class="file_list">
21
- <div
22
- v-for="(item, index) in uFileList"
23
- :key="index"
24
- class="file_card"
25
- >
26
- <img v-if="(item.file_type).toLocaleLowerCase().includes('pdf')" class="pdf" :src="pdfIcon" width="100%" alt="img" />
27
- <img v-else class="img" :src="item.file_url" width="100%" alt="img" />
28
- <div v-if="item.percent < 100" class="process">
29
- <progress-ring :percent="item.percent" />
30
- </div>
31
- <close-border-icon
32
- v-else
33
- class="close"
34
- @click.stop="clearFile(index)"
35
- />
36
- </div>
37
- <div
38
- v-if="uFileList.length < 4"
39
- class="file_add"
40
- @click.stop="triggerUploadInput"
41
- >
42
- <add-icon />
43
- </div>
44
- <div class="file_close" @click.stop="closeUpload">
45
- <close-icon />
46
- </div>
47
- </div>
48
- </div>
49
-
50
- <div class="om_operate">
51
- <textarea
52
- v-model="textValue"
53
- ref="txtEle"
54
- class="input"
55
- rows="1"
56
- :placeholder="defMsg.placeholder"
57
- @input="handleInput"
58
- @keyup.enter="sendMsg"
59
- @focus="handleFocus"
60
- @blur="handleBlur"
61
- />
62
- <div class="btn_group">
63
- <div class="btn" @click.stop="sendMsg">
64
- <send-icon v-if="isReq === '00'" :style="{ color: textValue ? '#039938' : '#ccc' }" />
65
- <send-loading-icon v-else
66
- :bg="loadingBtnInfo.bg"
67
- :color="loadingBtnInfo.color"
68
- />
69
- </div>
70
- </div>
71
- </div>
72
- </div>
73
- </div>
74
-
75
- <div class="om_extra" style="display: none">
76
- <input
77
- ref="captureInput"
78
- type="file"
79
- accept="image/*"
80
- capture="environment"
81
- style="display: none"
82
- @change="handleFile"
83
- />
84
-
85
- <input
86
- ref="uploadInput"
87
- type="file"
88
- accept="image/*,application/pdf"
89
- style="display: none"
90
- @change="handleFileChange"
91
- />
92
- <div
93
- v-for="card in extraList"
94
- :key="card.type"
95
- class="card"
96
- @click.stop="triggerUploadInput"
97
- >
98
- <div class="icon">
99
- <component :is="card.icon" />
100
- </div>
101
- <div class="text">{{ card.name }}</div>
102
- </div>
103
- <progress-ring :percent="15" />
104
- </div>
105
- <div class="om_ai_tips">{{ defMsg.aiTips}}</div>
106
- </div>
107
- </template>
108
-
109
- <script setup>
110
- import TagIcon from './icons/tagIcon.vue';
111
- import SendIcon from './icons/SendIcon.vue';
112
- import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
113
- import CameraIcon from './icons/cameraIcon.vue';
114
- import PictureIcon from './icons/pictureIcon.vue';
115
- import FileIcon from './icons/fileIcon.vue';
116
- import ProgressRing from './icons/progressRing.vue';
117
- import AddIcon from './icons/addIcon.vue';
118
- import CloseBorderIcon from './icons/closeBorderIcon.vue';
119
- import CloseIcon from './icons/CloseIcon.vue';
120
- import NewChat from './icons/newChat.vue';
121
- import SendLoadingIcon from "./icons/sendLoadingIcon.vue";
122
- const pdfIcon = 'https://prodstatic.weis1606.cn/api/smartFood/icon/pdf_icon.png';
123
- const extraList = [
124
- // { name: '相機', icon: CameraIcon, type: 'camera' },
125
- { name: '相冊', icon: PictureIcon, type: 'photo' },
126
- { name: '文件', icon: FileIcon, type: 'file' },
127
- ];
128
-
129
- const txtEle = ref(null);
130
- const uploadInput = ref(null);
131
- const captureInput = ref(null);
132
- const uploadPlane = ref(false);
133
-
134
- const uFileList = ref([]);
135
- const props = defineProps({
136
- modelValue: {
137
- type: String,
138
- default: '',
139
- },
140
- token: {
141
- type: String,
142
- required: true,
143
- },
144
- tagList: {
145
- type: Array,
146
- required: true,
147
- },
148
- newChat: {
149
- type: Boolean,
150
- default: false,
151
- },
152
- defMsg: {
153
- type: Object,
154
- required: true,
155
- },
156
- isReq:{
157
- type: String,
158
- default: '00'
159
- }
160
- });
161
- const Emits = defineEmits(['update:modelValue', 'send', 'tag', 'call']);
162
-
163
- const fetchOptions = computed(() => {
164
- return {
165
- headers: {
166
- Authorization: `Bearer ${props.token}`,
167
- 'Content-Type': 'multipart/form-data',
168
- },
169
- };
170
- });
171
-
172
- watch(
173
- () => props.modelValue,
174
- () => {
175
- resizeTextarea();
176
- },
177
- );
178
-
179
- /*
180
- * 00: 初始值;
181
- * 01: 已传达;
182
- * 02: 已发送;
183
- * 03:已接收;
184
- * 04: 读取中;
185
- * */
186
- const loadingBtnInfo = computed(() => {
187
- switch (props.isReq) {
188
- case '01':
189
- return { bg: '#fff', color: '#ccc'};
190
- case '02':
191
- return { bg: '#666', color: '#CDEBD7'};
192
- case '03':
193
- return { bg: '#ccc', color: '#fff'};
194
- case '04':
195
- return { bg: '#E5F4EB', color: '#fff'};
196
- }
197
- })
198
-
199
- const textValue = computed({
200
- get: () => {
201
- return props.modelValue;
202
- },
203
- set: (val) => {
204
- Emits('update:modelValue', val);
205
- resizeTextarea();
206
- },
207
- });
208
-
209
- onMounted(() => {
210
- resizeTextarea();
211
- });
212
- onUnmounted(() => {
213
- if (txtEle.value) {
214
- txtEle.value.style.height = 'auto'; // 恢复默认高度
215
- }
216
- });
217
-
218
- const handleInput = (event) => {
219
- textValue.value = event.target.value.replace(/^\n+|\n+$/g, '');
220
- };
221
- const handleTag = (info) => {
222
- if (info.type === 'upload') {
223
- showUpload();
224
- } else {
225
- Emits('tag', { ...info });
226
- }
227
- };
228
- const sendMsg = () => {
229
- if (!textValue.value) {
230
- return;
231
- }
232
- if (
233
- uFileList.value.length &&
234
- uFileList.value.findIndex((f) => f.percent < 100) > -1
235
- ) {
236
- Emits('call', {
237
- message: props.defMsg.uploadingTips,
238
- reason: 'is_uploading',
239
- value: 'toast',
240
- type: 'call',
241
- });
242
- return;
243
- }
244
- const list = [{ content: textValue.value, text: textValue.value }];
245
- console.log("====== u file list =======", uFileList.value);
246
- if (uFileList.value.length) {
247
- list.push({
248
- type: 'object_string',
249
- content: uFileList.value.map((file) => ({
250
- type: handleMsgType(file.file_type),
251
- name: file.file.name,
252
- file_id: file.data.id,
253
- file_url: file.file_url,
254
- })),
255
- });
256
- uploadPlane.value = false;
257
- }
258
- Emits('send', [...list]);
259
- clearAllFile();
260
- };
261
- const handleFile = (e) => {
262
- const file = e.target.files[0];
263
- const reader = new FileReader();
264
- reader.onload = () => (previewUrl.value = reader.result);
265
- reader.readAsDataURL(file);
266
- };
267
- const triggerUploadInput = () => {
268
- uploadInput.value ? uploadInput.value.click() : '';
269
- };
270
-
271
- const handleFileChange = (e) => {
272
- const selFile = e.target.files[0];
273
- console.log('=== file ===', e);
274
- if (selFile) {
275
- uFileList.value.push({
276
- file: selFile,
277
- file_type: selFile.type,
278
- file_url: URL.createObjectURL(selFile),
279
- size: (selFile.size / 1024).toFixed(2),
280
- percent: 0,
281
- data: {},
282
- });
283
- console.log('=== 文件列表 ===', uFileList.value);
284
- handleUpload(uFileList.value.length - 1);
285
- }
286
- };
287
- const handleUpload = async (idx) => {
288
- const file = uFileList.value[idx].file;
289
- console.log('========', file);
290
- if (!textValue.value) {
291
- textValue.value = props.defMsg.fileText;
292
- }
293
- const formDate = new FormData();
294
- formDate.append('file', file);
295
- const xhr = new XMLHttpRequest();
296
- xhr.open('POST', 'https://api.coze.cn/v1/files/upload');
297
- xhr.setRequestHeader(
298
- 'Authorization',
299
- fetchOptions.value.headers.Authorization,
300
- );
301
- xhr.upload.onprogress = (e) => {
302
- if (e.lengthComputable) {
303
- const percent = Math.round((e.loaded / e.total) * 100);
304
- console.log(`======进度======:${percent}%`);
305
- uFileList.value[idx].percent = percent;
306
- }
307
- };
308
- xhr.onreadystatechange = function () {
309
- console.log('============', xhr);
310
- if (xhr.readyState === XMLHttpRequest.DONE) {
311
- if (xhr.status === 200) {
312
- console.log('上传成功:', xhr.responseText);
313
- const res = JSON.parse(xhr.response);
314
- uFileList.value[idx].data = res.data;
315
- } else {
316
- console.error('上传失败:', xhr.status);
317
- }
318
- }
319
- };
320
- xhr.send(formDate);
321
- };
322
- const showUpload = () => {
323
- clearAllFile(true);
324
- uploadPlane.value = true;
325
- };
326
- const closeUpload = () => {
327
- clearAllFile(true);
328
- uploadPlane.value = false;
329
- };
330
- const clearAllFile = (deep = false) => {
331
- if (deep) {
332
- for (let i = uFileList.value.length - 1; i >= 0; i -= 1) {
333
- clearFile(i);
334
- }
335
- }
336
- uploadInput.value ? (uploadInput.value.value = '') : '';
337
-
338
- uFileList.value = [];
339
- };
340
-
341
- const clearFile = (idx) => {
342
- URL.revokeObjectURL(uFileList.value[idx].file_url);
343
- uFileList.value.splice(idx, 1);
344
- uploadInput.value ? (uploadInput.value.value = '') : '';
345
- };
346
-
347
- const newChatFunc = () => {
348
- Emits('call', {
349
- type: 'new_chat',
350
- });
351
- };
352
-
353
- const resizeTextarea = () => {
354
- nextTick(() => {
355
- if (txtEle.value) {
356
- txtEle.value.style.height = 'auto';
357
- txtEle.value.style.height =
358
- Math.min(txtEle.value.scrollHeight, 72) + 'px';
359
- }
360
- });
361
- };
362
-
363
- const handleFocus = () => {
364
- nextTick(() => {
365
- window.scrollTo({
366
- top: Math.round(
367
- 0.7 * window.innerHeight + 0.5476 * window.innerWidth - 416.4,
368
- ), // 滚动到页面的总高度
369
- behavior: 'smooth', // 平滑滚动效果
370
- });
371
- });
372
- };
373
- const handleMsgType = (file_type) => {
374
- /* text:文本类型。
375
- * file:文件类型。
376
- * image:图片类型。
377
- * audio:音频类型。
378
- * */
379
- if(file_type.includes('image')) {
380
- return 'image'
381
- }else if(file_type.includes('application')) {
382
- return 'file'
383
- }else if(file_type.includes('audio')) {
384
- return 'audio'
385
- }
386
- }
387
- const handleBlur = () => {};
388
- </script>
389
-
390
- <style scoped lang="less">
391
- @import './OperateModule';
392
- </style>
@@ -1,114 +0,0 @@
1
- <template>
2
- <div class="card" style="margin-top: 15px">
3
- <div class="row">
4
- <div class="name">每日攝入能量</div>
5
- <div class="content">{{ info.totalIntake }} kcal</div>
6
- </div>
7
- </div>
8
- <div v-for="cate in info.planDetailList" :key="category" class="card">
9
- <div class="title">{{ textMap[cate.category] }}</div>
10
- <div class="row">
11
- <div class="name">{{ textMap[cate.category] }}熱量</div>
12
- <div class="content">{{ cate.totalKcal }} kcal</div>
13
- </div>
14
- <div class="sep" />
15
- <div class="row">
16
- <div class="name">{{ textMap.carbohydrateTotal }}</div>
17
- <div class="content">{{ cate.carbohydrateTotal }} g</div>
18
- </div>
19
- <div class="row">
20
- <div class="name">{{ textMap.proteinTotal }}</div>
21
- <div class="content">{{ cate.proteinTotal }} g</div>
22
- </div>
23
- <div class="row">
24
- <div class="name">{{ textMap.fatTotal }}</div>
25
- <div class="content">{{ cate.fatTotal }} g</div>
26
- </div>
27
- </div>
28
- <div class="btn_group">
29
- <div class="btn btn_2" @click.stop="handleSel">用該方案配餐</div>
30
- </div>
31
- </template>
32
-
33
- <script setup>
34
- const textMap = {
35
- '01': '早餐',
36
- '02': '午餐',
37
- '03': '晚餐',
38
- '04': '加餐',
39
- carbohydrateTotal: '碳水化合物',
40
- proteinTotal: '蛋白質',
41
- fatTotal: '脂肪',
42
- };
43
-
44
- const props = defineProps({
45
- info: {
46
- type: Object,
47
- required: true,
48
- },
49
- defMsg: {
50
- type: Object,
51
- required: true,
52
- },
53
- });
54
- const Emits = defineEmits(['select']);
55
- const handleSel = () => {
56
- Emits('select', {});
57
- };
58
- </script>
59
-
60
- <style scoped lang="less">
61
- .card {
62
- padding: 10px 15px;
63
- margin-bottom: 10px;
64
- background-color: #fff;
65
- border-radius: 10px;
66
- .title {
67
- font-size: 14px;
68
- font-weight: 600;
69
- line-height: 24px;
70
- }
71
- .row {
72
- .flexrbc();
73
- margin: 10px 0;
74
- }
75
- .sep {
76
- border-bottom: 1px solid #ddd;
77
- }
78
- .name {
79
- font-weight: 400;
80
- font-size: 14px;
81
- color: #666;
82
- line-height: 24px;
83
- }
84
- .content {
85
- .name();
86
- color: #000;
87
- font-weight: 600;
88
- }
89
- }
90
- .btn {
91
- cursor: pointer;
92
- width: 100%;
93
- height: 38px;
94
- line-height: 38px;
95
- background-color: #e6f5eb;
96
- border-radius: 19px;
97
- text-align: center;
98
- font-weight: 600;
99
- font-size: 13px;
100
- color: #039938;
101
-
102
- &_2 {
103
- color: #fff;
104
- background-color: #039938;
105
- }
106
-
107
- &_group {
108
- display: grid;
109
- grid-template-columns: 1fr;
110
- grid-column-gap: 10px;
111
- margin-top: 20px;
112
- }
113
- }
114
- </style>
@@ -1,72 +0,0 @@
1
- <template>
2
- <div class="sc_wrap" @click.stop="handleSelStore">
3
- <div
4
- class="img"
5
- :style="{
6
- background: `url(${
7
- info.signUrl || defImg
8
- }?x-oss-process=image/resize,w_144) no-repeat center`,
9
- backgroundSize: 'cover',
10
- }"
11
- @click.stop="previewImg([info.signUrl || defImg])"
12
- />
13
- <div>
14
- <div class="name">{{ info.hpName }}</div>
15
- <div class="address">{{ info.address }}</div>
16
- </div>
17
- </div>
18
- </template>
19
-
20
- <script setup>
21
- import { previewImg } from '../../utils/imagesViewer';
22
-
23
- const defImg =
24
- 'https://prodstatic.weis1606.cn/api/smartFood/images/logo_img.png';
25
- const props = defineProps({
26
- info: {
27
- type: Object,
28
- required: true,
29
- },
30
- });
31
- const Emits = defineEmits(['select']);
32
- const handleSelStore = () => {
33
- Emits('select', {
34
- type: 'chat',
35
- content: props.info.hpName,
36
- text: props.info.hpName,
37
- });
38
- };
39
- </script>
40
-
41
- <style scoped lang="less">
42
- .sc_wrap {
43
- .flexrss();
44
- gap: 10px;
45
- cursor: default;
46
- padding: 10px;
47
- margin: 10px 0;
48
- border-radius: 10px;
49
- background-color: #fff;
50
- .img {
51
- cursor: pointer;
52
- width: 72px;
53
- height: 72px;
54
- flex-shrink: 0;
55
- border-radius: 10px;
56
- background-color: #d9d9d9;
57
- }
58
- .name {
59
- font-weight: 600;
60
- font-size: 14px;
61
- color: #000;
62
- line-height: 16px;
63
- }
64
- .address {
65
- margin-top: 10px;
66
- font-weight: 400;
67
- font-size: 10px;
68
- color: #666;
69
- line-height: 12px;
70
- }
71
- }
72
- </style>
@@ -1,27 +0,0 @@
1
- <template>
2
- <div>请选择一个门店</div>
3
- <template v-for="info in list" :key="info.hpName">
4
- <store-card :info="info" @select="handleSel" />
5
- </template>
6
- </template>
7
-
8
- <script setup>
9
- import StoreCard from './StoreCard.vue';
10
- // import data from './mock';
11
- // import { computed } from 'vue';
12
- // const list = computed(() => {
13
- // return data.storeList;
14
- // });
15
- const props = defineProps({
16
- list: {
17
- type: Array,
18
- required: true,
19
- },
20
- });
21
- const Emits = defineEmits(['select']);
22
- const handleSel = (info) => {
23
- Emits('select', { ...info });
24
- };
25
- </script>
26
-
27
- <style scoped></style>