ai-read-over-pro 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 (41) hide show
  1. package/README.md +33 -0
  2. package/components/demo/api/index.js +81 -0
  3. package/components/demo/index.js +7 -0
  4. package/components/demo/plugins/cache.js +77 -0
  5. package/components/demo/src/chat-tools.vue +275 -0
  6. package/components/demo/src/main.vue +378 -0
  7. package/components/demo/src/member-table.vue +204 -0
  8. package/components/demo/src/read-over.vue +238 -0
  9. package/components/demo/src/tab-filter.vue +223 -0
  10. package/components/demo/static/bg-img.svg +10 -0
  11. package/components/demo/static/cai-active.png +0 -0
  12. package/components/demo/static/cai.png +0 -0
  13. package/components/demo/static/correct.png +0 -0
  14. package/components/demo/static/error.png +0 -0
  15. package/components/demo/static/filter-block.svg +23 -0
  16. package/components/demo/static/filter-block_hover.svg +23 -0
  17. package/components/demo/static/filter-block_selected.svg +23 -0
  18. package/components/demo/static/filter.png +0 -0
  19. package/components/demo/static/logo.png +0 -0
  20. package/components/demo/static/robot.png +0 -0
  21. package/components/demo/static/send-icon.png +0 -0
  22. package/components/demo/static/zan-active.png +0 -0
  23. package/components/demo/static/zan.png +0 -0
  24. package/components/demo/utils/aes-utils.js +35 -0
  25. package/components/demo/utils/config.js +42 -0
  26. package/components/demo/utils/constants.js +13 -0
  27. package/components/demo/utils/request.js +69 -0
  28. package/components/index.js +15 -0
  29. package/dist/ai-read-over-pro.common.js +12858 -0
  30. package/dist/ai-read-over-pro.common.js.map +1 -0
  31. package/dist/ai-read-over-pro.css +1 -0
  32. package/dist/ai-read-over-pro.umd.js +12877 -0
  33. package/dist/ai-read-over-pro.umd.js.map +1 -0
  34. package/dist/ai-read-over-pro.umd.min.js +23 -0
  35. package/dist/ai-read-over-pro.umd.min.js.map +1 -0
  36. package/dist/demo.html +1 -0
  37. package/dist/img/bg-img.a3a40197.svg +10 -0
  38. package/dist/img/filter-block.6f369747.svg +23 -0
  39. package/dist/img/filter-block_hover.5314be0a.svg +23 -0
  40. package/dist/img/filter-block_selected.f523d7f3.svg +23 -0
  41. package/package.json +44 -0
@@ -0,0 +1,378 @@
1
+ <template>
2
+ <div class="ai-contain" v-if="visible">
3
+ <div class="bg-image"></div>
4
+ <div class="ai-contain-header">
5
+ <div class="logo-title">
6
+ <img src="../static/logo.png" alt="" style="width: 48px; height: 48px">
7
+ <span class="title-font">智能批阅</span>
8
+ </div>
9
+ <div class="icon-close" @click="closeMessage">
10
+ <i class="el-icon-close"></i>
11
+ </div>
12
+ </div>
13
+ <div class="wrap">
14
+ <div class="filter-wrap" v-if="showFilter">
15
+ <tab-filter :tab-data="listData"
16
+ :replyData="replyCache"
17
+ @on-filter-change="filterChange"
18
+ @on-close="tabFilterClose"/>
19
+ </div>
20
+ <div class="normal-wrap" :class="{'full-width': !showFilter }">
21
+ <div class="label-wrap" style="margin-top: 16px" ref="labelContainer">
22
+ <div class="label-container">
23
+ <div class="label-item"
24
+ v-if="isPerson && !showFilter"
25
+ @click="showFilterMethod"
26
+ style="width: 32px; padding: 0; line-height: 42px">
27
+ <img src="../static/filter.png" style="width: 24px; height: 24px"/>
28
+ </div>
29
+ <div class="label-item" v-for="item in showTableList"
30
+ :key="item.id"
31
+ :title="item.title"
32
+ :class="{'label-item-active': item.active}"
33
+ @click="tabClick(item)">
34
+ {{ item.title }}
35
+ <div class="loading-block" v-if="!replyCache[item.id]">
36
+ <i class="el-icon-loading"></i>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ <div class="label-item label-down"
41
+ v-if="showMoreButton"
42
+ @click="stretchContainer"
43
+ style="width: 32px">
44
+ <span v-if="!stretch">...</span>
45
+ <i class="el-icon-d-arrow-left" style="transform: rotate(90deg)" v-else></i>
46
+ </div>
47
+ </div>
48
+ <div class="ai-main-content">
49
+ <read-over :exercises-data="activeItem"
50
+ :analyze-data="analyzeData"
51
+ @on-reanswer="onReanswer"
52
+ @on-noty-apply="notyApply"/>
53
+ <div class="member-table" v-if="stretch">
54
+ <member-table :check-data="showTableList"
55
+ :show-data="tabList"
56
+ :replyCache="replyCache"
57
+ @on-select-member="selectMember" />
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </template>
64
+ <script>
65
+ import ReadOver from './read-over.vue';
66
+ import { getUserInfo } from '../utils/config';
67
+ import { generateReview, registerSse, criticismApply, reanswerReview } from '../api/index';
68
+ import Cookies from "js-cookie";
69
+ import TabFilter from './tab-filter.vue';
70
+ import MemberTable from './member-table.vue';
71
+
72
+ export default {
73
+ name: 'AiReadOver',
74
+ components: {
75
+ ReadOver,
76
+ TabFilter,
77
+ MemberTable
78
+ },
79
+ props: {
80
+ visible: {
81
+ type: Boolean,
82
+ default: false,
83
+ },
84
+ listData: {
85
+ type: Array,
86
+ default: () => []
87
+ },
88
+ courseId: {
89
+ type: String,
90
+ default: '',
91
+ },
92
+ isPerson: {
93
+ type: Boolean,
94
+ default: false,
95
+ }
96
+ },
97
+ data() {
98
+ return {
99
+ stretch: false,
100
+ showFilter: false,
101
+ showMoreButton: false, // 是否显示下拉框
102
+ replyCache: {}, // 记录所有回复信息
103
+ activeItem: {}, // 当前记录的item
104
+ analyzeData: {}, // 当前回复信息
105
+ sseSessionId: '', // sse会话id,
106
+ tabList: [],
107
+ showTableList: []
108
+ }
109
+ },
110
+ watch: {
111
+ visible() {
112
+ if (this.visible) {
113
+ this.sseSessionId = new Date().getTime().toString();
114
+ this.tabList = this.listData;
115
+ setTimeout(() => {
116
+ this.dealTableList();
117
+ this.sendAiInfo();
118
+ })
119
+ } else {
120
+ this.showFilter = false;
121
+ }
122
+ },
123
+ listData: {
124
+ handler() {
125
+ this.tabList = this.listData;
126
+ },
127
+ immediate: true
128
+ }
129
+ },
130
+ mounted() {
131
+ if (!Cookies.get("token")) {
132
+ return this.$message.warning('未获取到登录信息,请重新登录');
133
+ }
134
+ this.messageList = [];
135
+ getUserInfo(Cookies.get("token"));
136
+ },
137
+ methods: {
138
+ resizeFirstActive() {
139
+ if (!this.showTableList || this.showTableList.length < 1) {
140
+ this.analyzeData = null;
141
+ return;
142
+ }
143
+ this.showTableList.map((item) => item.active = false);
144
+ this.showTableList[0].active = true;
145
+ this.activeItem = this.showTableList[0];
146
+ this.analyzeData = this.replyCache[this.showTableList[0].id];
147
+ },
148
+ closeMessage() {
149
+ this.$emit('close');
150
+ },
151
+ tabClick(tab) {
152
+ this.tabList.map((item) => item.active = false);
153
+ tab.active = true;
154
+ this.$forceUpdate();
155
+ this.activeItem = tab;
156
+ this.analyzeData = this.replyCache[tab.id];
157
+ },
158
+ stretchContainer() {
159
+ this.stretch = !this.stretch;
160
+ },
161
+ messageBack(message, type) {
162
+ const { bizId, comments: [backData] } = message;
163
+ const { content } = backData;
164
+ let currentId = bizId;
165
+ backData.jsonContent = JSON.parse(content);
166
+ if (type === 'reanswer') {
167
+ currentId = this.activeItem.id;
168
+ }
169
+ this.$set(this.replyCache, currentId, backData);
170
+ // 更新当前值
171
+ this.analyzeData = this.replyCache[this.activeItem.id];
172
+ },
173
+ async sendAiInfo() {
174
+ registerSse(this.sseSessionId, this.messageBack);
175
+ const paramsData = [];
176
+ this.listData.map((item) => {
177
+ paramsData.push({
178
+ bizId: item.id,
179
+ question: item.question,
180
+ score: item.score,
181
+ answer: item.answer,
182
+ answerer: item.title,
183
+ })
184
+ })
185
+ await generateReview(paramsData, this.sseSessionId, this.courseId);
186
+ },
187
+ async notyApply(data) {
188
+ const { id } = data;
189
+ await criticismApply(id);
190
+ this.analyzeData.accepted = true;
191
+ this.$emit('on-noty-apply', data);
192
+ },
193
+ async onReanswer(list) {
194
+ this.analyzeData = {};
195
+ this.replyCache[this.activeItem.id] = null;
196
+ await reanswerReview(this.sseSessionId, list.id);
197
+ },
198
+ tabFilterClose(data) {
199
+ this.showFilter = false;
200
+ this.tabList = data;
201
+ this.resizeFirstActive();
202
+ setTimeout(() => {
203
+ this.dealTableList();
204
+ });
205
+ },
206
+ filterChange(data) {
207
+ this.tabList = data;
208
+ this.resizeFirstActive();
209
+ this.stretch = false;
210
+ setTimeout(() => {
211
+ this.dealTableList();
212
+ });
213
+ },
214
+ showFilterMethod() {
215
+ this.showFilter = true;
216
+ setTimeout(() => {
217
+ this.dealTableList();
218
+ });
219
+ },
220
+ dealTableList() {
221
+ const labelContainer = this.$refs.labelContainer;
222
+ if (!labelContainer) return;
223
+ const BLOCK_WIDTH = 80; // 和 css 值保持一致
224
+ let width = labelContainer.clientWidth;
225
+ if (this.isPerson) {
226
+ width -= 40;
227
+ }
228
+ const blockCount = Math.floor(width / BLOCK_WIDTH);
229
+ this.showMoreButton = blockCount < this.tabList.length;
230
+ this.showTableList = this.tabList.slice(0, blockCount - 2);
231
+ this.resizeFirstActive();
232
+ },
233
+ selectMember(data) {
234
+ this.showTableList = data;
235
+ this.resizeFirstActive();
236
+ }
237
+ }
238
+ }
239
+ </script>
240
+ <style lang="scss" scoped>
241
+ .ai-contain {
242
+ width: 1000px;
243
+ height: 100%;
244
+ border-radius: 16px;
245
+ box-shadow: 0 1px 8px rgba(32, 40, 64, 0.32);
246
+ padding: 16px 16px 16px 16px;
247
+ box-sizing: border-box;
248
+ position: relative;
249
+ background-color: rgba(232, 240, 248, 1);
250
+ }
251
+ .ai-contain-header {
252
+ position: relative;
253
+ z-index: 1;
254
+ display: flex;
255
+ justify-content: space-between;
256
+ }
257
+ .logo-title {
258
+ font-weight: 700;
259
+ color: #202840;
260
+ font-size: 18px;
261
+ }
262
+ .title-font {
263
+ display: inline-block;
264
+ vertical-align: top;
265
+ margin-top: 12px;
266
+ margin-left: 12px;
267
+ color: rgb(40, 128, 240);
268
+ }
269
+ .icon-close {
270
+ cursor: pointer;
271
+ position: relative;
272
+ right: 0;
273
+ i {
274
+ font-weight: bold !important;
275
+ }
276
+ }
277
+ .ai-main-content {
278
+ position: relative;
279
+ width: 100%;
280
+ height: calc(100% - 32px - 40px - 16px);
281
+ display: flex;
282
+ z-index: 1;
283
+ padding: 16px 0 16px 8px;
284
+ }
285
+ .bg-image {
286
+ position: absolute;
287
+ top: 0;
288
+ left: 0;
289
+ width: 100%;
290
+ height: 248px;
291
+ background: linear-gradient(to bottom, rgba(96, 96, 244, .1), rgba(44, 144, 240, 0));
292
+ border-radius: 16px 0;
293
+ }
294
+ .label-wrap {
295
+ display: flex;
296
+ padding-left: 8px;
297
+ padding-right: 24px;
298
+ align-items: end;
299
+ justify-content: space-between;
300
+ .label-container {
301
+ display: flex;
302
+ flex-wrap: wrap;
303
+ height: 40px;
304
+ overflow: hidden;
305
+ }
306
+ .label-item {
307
+ font-size: 14px;
308
+ color: rgba(96, 96, 224, 1);
309
+ border: 1px solid #797be4;
310
+ width: 80px;
311
+ cursor: pointer;
312
+ height: 32px;
313
+ line-height: 32px;
314
+ padding: 0 8px;
315
+ text-align: center;
316
+ box-sizing: border-box;
317
+ border-radius: 8px;
318
+ margin-bottom: 8px;
319
+ overflow: hidden;
320
+ text-overflow: ellipsis;
321
+ white-space: nowrap;
322
+ position: relative;
323
+ &:hover {
324
+ font-weight: 600;
325
+ border-color: #6060e0;
326
+ }
327
+ }
328
+ .loading-block {
329
+ position: absolute;
330
+ right: 2px;
331
+ bottom: 14px;
332
+ width: 16px;
333
+ height: 16px;
334
+ }
335
+ .label-down {
336
+ position: relative;
337
+ bottom: 0;
338
+ }
339
+ .label-item-active {
340
+ color: #fff;
341
+ background: linear-gradient(90deg, rgba(0, 144, 240, 1) 0%, rgba(144, 48, 240, 1) 100%);
342
+ &:hover {
343
+ font-weight: 400;
344
+ border-color: #797be4;
345
+ }
346
+ }
347
+ .label-item {
348
+ margin-right: 8px;
349
+ }
350
+ }
351
+ .wrap {
352
+ display: flex;
353
+ height: calc(100% - 53px);
354
+ position: relative;
355
+ z-index: 1;
356
+ .filter-wrap {
357
+ width: 100px;
358
+ height: 100%;
359
+ padding-top: 64px;
360
+ box-sizing: border-box;
361
+ }
362
+ .normal-wrap {
363
+ width: calc(100% - 100px);
364
+ height: 100%;
365
+ }
366
+ .full-width {
367
+ width: 100%;
368
+ }
369
+ .member-table {
370
+ position: absolute;
371
+ top: 0;
372
+ right: 12px;
373
+ width: 320px;
374
+ height: 100%;
375
+ z-index: 999999;
376
+ }
377
+ }
378
+ </style>
@@ -0,0 +1,204 @@
1
+ <template>
2
+ <div class="member-table-contain" @keyup.enter="searchData">
3
+ <el-input
4
+ placeholder="请输入内容"
5
+ v-model="searchInput">
6
+ <i slot="suffix" class="el-input__icon el-icon-search" @click="searchData"></i>
7
+ </el-input>
8
+ <div class="content">
9
+ <div class="member-list"
10
+ v-for="item in activeData"
11
+ :class="{'member-list-selected': selectedMap[item.id]}"
12
+ :key="item.id"
13
+ @click="selectMember(item)">
14
+ <div>
15
+ <span class="loading-block" v-if="!replyCache[item.id]">
16
+ <i class="el-icon-loading"></i>
17
+ </span>
18
+ {{ item.title }}
19
+ </div>
20
+ <span class="member-list-icon">
21
+ <i class="el-icon-success icon-select"></i>
22
+ <i class="el-icon-circle-plus-outline icon-hover"></i>
23
+ </span>
24
+ </div>
25
+ </div>
26
+ <div class="pagination">
27
+ <el-pagination
28
+ layout="prev, pager, next"
29
+ :small="true"
30
+ :page-size="pageSize"
31
+ :current-page="pageNo"
32
+ :total="cacheShowData.length"
33
+ @current-change="setActiveData">
34
+ </el-pagination>
35
+ </div>
36
+ </div>
37
+ </template>
38
+ <script>
39
+ export default {
40
+ name: 'MemberTable',
41
+ props: {
42
+ checkData: {
43
+ type: Array,
44
+ default: () => []
45
+ },
46
+ showData: {
47
+ type: Array,
48
+ default: () => []
49
+ },
50
+ replyCache: {
51
+ type: Object,
52
+ default: () => {}
53
+ }
54
+ },
55
+ watch: {
56
+ checkData: {
57
+ handler() {
58
+ this.selectedMap = {};
59
+ this.checkData.map((item) => {
60
+ this.selectedMap[item.id] = item;
61
+ });
62
+ this.selectedData = [...this.checkData];
63
+ this.$forceUpdate();
64
+ },
65
+ immediate: true
66
+ },
67
+ showData: {
68
+ handler() {
69
+ this.cacheShowData = [...this.showData];
70
+ this.setActiveData();
71
+ },
72
+ immediate: true
73
+ },
74
+ },
75
+ data() {
76
+ return {
77
+ searchInput: '',
78
+ pageNo: 1,
79
+ pageSize: 10,
80
+ activeData: [],
81
+ selectedData: [],
82
+ selectedMap: {},
83
+ cacheShowData: [],
84
+ }
85
+ },
86
+ methods: {
87
+ setActiveData(pageNo) {
88
+ if (pageNo) this.pageNo = pageNo;
89
+ this.activeData = this.cacheShowData.slice(this.pageSize * (this.pageNo - 1), this.pageSize * this.pageNo);
90
+ },
91
+ selectMember(item) {
92
+ if (this.selectedMap[item.id]) return;
93
+ this.selectedData.unshift(item);
94
+ this.selectedData.pop();
95
+ this.$emit('on-select-member', this.selectedData);
96
+ },
97
+ searchData() {
98
+ this.pageNo = 1;
99
+ this.cacheShowData = this.searchInput === '' ? [...this.showData] :
100
+ this.showData.filter((item)=> item.title.indexOf(this.searchInput) >- 1);
101
+ this.setActiveData();
102
+ }
103
+ },
104
+ }
105
+ </script>
106
+ <style lang="scss" scoped>
107
+ .member-table-contain {
108
+ width: 100%;
109
+ height: 100%;
110
+ padding: 24px;
111
+ padding-bottom: 8px;
112
+ box-sizing: border-box;
113
+ background: linear-gradient(168.988deg, rgb(255, 255, 255) 4%, rgb(238, 238, 255) 100%);
114
+ border-radius: 12px;
115
+ box-shadow: rgba(48, 96, 144, 0.48) 0 0 16px;
116
+ ::v-deep(.el-input__inner) {
117
+ border-radius: 24px;
118
+ }
119
+ .el-icon-search {
120
+ cursor: pointer;
121
+ color: rgba(44,44,44,1);
122
+ }
123
+ .member-list {
124
+ display: flex;
125
+ justify-content: space-between;
126
+ height: 40px;
127
+ border-radius: 26px;
128
+ padding: 10px 16px;
129
+ box-sizing: border-box;
130
+ font-size: 14px;
131
+ cursor: pointer;
132
+ &:hover {
133
+ background-color: rgba(32, 40, 64, 0.08);
134
+ .icon-hover {
135
+ display: block;
136
+ }
137
+ }
138
+ }
139
+ .member-list-icon {
140
+ font-size: 22px;
141
+ display: inline-block;
142
+ line-height: 0;
143
+ }
144
+ .icon-select,.icon-hover {
145
+ display: none;
146
+ }
147
+ .member-list-selected {
148
+ .icon-select {
149
+ display: block;
150
+ }
151
+ &:hover {
152
+ .icon-hover {
153
+ display: none;
154
+ }
155
+ }
156
+ }
157
+ }
158
+ .content {
159
+ margin: 8px 0;
160
+ height: calc(100% - 32px - 40px - 16px);
161
+ overflow-y: auto;
162
+ /* 滚动条轨道样式 */
163
+ &::-webkit-scrollbar {
164
+ width: 4px;
165
+ /* 设置滚动条宽度 */
166
+ // background-color: #f1f1f1;
167
+ border-radius: 10px;
168
+ }
169
+
170
+ /* 滚动条轨道 */
171
+ &::-webkit-scrollbar-track {
172
+ background: transparent; /* 设置轨道背景为透明 */
173
+ }
174
+
175
+ /* 滚动条滑块样式 */
176
+ &::-webkit-scrollbar-thumb {
177
+ background: rgba(96, 128, 240, 0.6); /* 设置拖动块颜色 */
178
+ border-radius: 4px;
179
+ -webkit-box-shadow: inset 0 0 2px transparent;
180
+ -webkit-transition: all 0.2s linear;
181
+ transition: all 0.2s linear;
182
+ }
183
+
184
+ /* 滚动条滑块hover状态样式 */
185
+ &::-webkit-scrollbar-thumb:hover {
186
+ background: rgba(96, 128, 240, 0.5); /* 加深颜色 */
187
+ }
188
+ }
189
+ .pagination {
190
+ text-align: center;
191
+ ::v-deep(.el-pager li) {
192
+ background: transparent;
193
+ }
194
+ ::v-deep(.el-pagination .btn-next) {
195
+ background: transparent;
196
+ }
197
+ ::v-deep(.el-pagination .btn-prev) {
198
+ background: transparent;
199
+ }
200
+ ::v-deep(.el-pagination button:disabled) {
201
+ background: transparent;
202
+ }
203
+ }
204
+ </style>