ai-read-over-pro 0.0.17 → 0.0.19

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.
@@ -77,6 +77,14 @@ export const loopPoll = (data) => {
77
77
  });
78
78
  }
79
79
 
80
+ export const analysisSave = (data) => {
81
+ return request({
82
+ url: prefix + '/criticism/analysis/save',
83
+ method: 'post',
84
+ data,
85
+ });
86
+ }
87
+
80
88
  // export const registerSse = (sseSessionId, fn, successFn) => {
81
89
  // const source = new EventSourcePolyfill(baseURL + prefix + '/sse?id=' + sseSessionId, {
82
90
  // headers: {
@@ -0,0 +1,301 @@
1
+ <template>
2
+ <div class="ri-wrap">
3
+ <!-- 公式弹窗 -->
4
+ <el-popover
5
+ v-model="formulaVisible"
6
+ popper-class="ri-formula-popover"
7
+ placement="top-start"
8
+ trigger="manual"
9
+ >
10
+ <div class="ri-formula-container">
11
+ <iframe
12
+ :src="`https://zjyw.icve.com.cn/kityformula-editor/kityFormula.html?c=${formulaValue}`"
13
+ ref="editorFrame"
14
+ class="ri-formula-iframe"
15
+ ></iframe>
16
+ <el-button type="primary" size="small" class="ri-formula-save" @click="saveFormula">保存</el-button>
17
+ </div>
18
+ <!-- 触发锚点(隐藏,通过 v-model 手动控制) -->
19
+ <span slot="reference"></span>
20
+ </el-popover>
21
+
22
+ <!-- 编辑器容器 -->
23
+ <div
24
+ class="ri-editor-wrap"
25
+ :style="{ minHeight: height + 'px' }"
26
+ :class="{ 'ri-editor-focus': isFocused }"
27
+ >
28
+ <Editor
29
+ class="ri-editor"
30
+ :style="{ minHeight: height + 'px' }"
31
+ :defaultConfig="editorConfig"
32
+ :mode="'simple'"
33
+ @onCreated="onCreated"
34
+ @onChange="onChange"
35
+ @onFocus="isFocused = true"
36
+ @onBlur="isFocused = false"
37
+ @customPaste="customPaste"
38
+ />
39
+ </div>
40
+
41
+ <!-- 插入公式按钮 -->
42
+ <div class="ri-toolbar">
43
+ <span class="ri-formula-btn" @click="openFormula">
44
+ <img src="../static/formula.png" class="ri-fx-img" alt="fx" />
45
+ 插入公式
46
+ </span>
47
+ </div>
48
+ </div>
49
+ </template>
50
+
51
+ <script>
52
+ import { Boot } from '@wangeditor/editor';
53
+ import formulaModule from '@wangeditor/plugin-formula';
54
+ import { Editor } from '@wangeditor/editor-for-vue';
55
+
56
+ let _booted = false;
57
+ function ensureBoot() {
58
+ if (!_booted) {
59
+ try {
60
+ Boot.registerModule(formulaModule);
61
+ } catch (e) {}
62
+ _booted = true;
63
+ }
64
+ }
65
+ ensureBoot();
66
+
67
+ export default {
68
+ name: 'RichInput',
69
+ components: { Editor },
70
+ props: {
71
+ value: {
72
+ type: String,
73
+ default: '',
74
+ },
75
+ placeholder: {
76
+ type: String,
77
+ default: '请输入内容,支持公式编辑',
78
+ },
79
+ height: {
80
+ type: Number,
81
+ default: 90,
82
+ },
83
+ },
84
+ data() {
85
+ return {
86
+ editor: null,
87
+ isFocused: false,
88
+ formulaVisible: false,
89
+ formulaValue: '',
90
+ editorConfig: {
91
+ placeholder: this.placeholder,
92
+ hoverbarKeys: {
93
+ formula: {
94
+ menuKeys: [],
95
+ },
96
+ },
97
+ },
98
+ };
99
+ },
100
+ watch: {
101
+ value(val) {
102
+ if (!this.editor) return;
103
+ try {
104
+ const current = this.editor.getHtml();
105
+ if (val !== current) {
106
+ // 直接 nextTick 就够,因为此时编辑器已经初始化完成
107
+ this.$nextTick(() => {
108
+ try {
109
+ this.editor.setHtml(val || '<p><br></p>');
110
+ } catch (e) {}
111
+ });
112
+ }
113
+ } catch (e) {}
114
+ },
115
+ },
116
+ mounted() {
117
+ window.addEventListener('message', this.latexMessage);
118
+ },
119
+ beforeDestroy() {
120
+ window.removeEventListener('message', this.latexMessage);
121
+ if (this.editor) {
122
+ this.editor.destroy();
123
+ }
124
+ },
125
+ methods: {
126
+ onCreated(editor) {
127
+ this.editor = Object.seal(editor);
128
+ },
129
+
130
+ onChange(editor) {
131
+ this.$emit('input', editor.getHtml());
132
+ },
133
+
134
+ openFormula() {
135
+ if (!this.editor) return;
136
+ this.editor.focus();
137
+ this.formulaValue = '';
138
+ this.formulaVisible = true;
139
+ },
140
+
141
+ saveFormula() {
142
+ if (this.$refs.editorFrame) {
143
+ this.$refs.editorFrame.contentWindow.postMessage('message', '*');
144
+ }
145
+ setTimeout(() => {
146
+ this.formulaVisible = false;
147
+ }, 100);
148
+ },
149
+
150
+ latexMessage(event) {
151
+ if (!this.formulaVisible) return;
152
+ const { mceAction, content } = event.data || {};
153
+ if (mceAction !== 'insertContent') return;
154
+ if (!content) return;
155
+
156
+ const match = content.match(/data-latex="([^"]+)"/);
157
+ if (!match) return;
158
+
159
+ let latex = match[1].replace(/\s/g, '');
160
+ if (latex === '\\placeholder') return;
161
+
162
+ if (!this.editor) return;
163
+
164
+ try {
165
+ this.editor.restoreSelection(); // 加 try-catch 兜底
166
+ } catch (e) {
167
+ // restoreSelection 失败时,把光标移到末尾
168
+ this.editor.focus(true);
169
+ }
170
+
171
+ const formulaNode = {
172
+ type: 'formula',
173
+ value: latex,
174
+ children: [{ text: '' }],
175
+ };
176
+ this.editor.insertNode(formulaNode);
177
+ },
178
+
179
+ customPaste(editor, event, callback) {
180
+ const text = event.clipboardData.getData('text/plain');
181
+ editor.insertText(text);
182
+ event.preventDefault();
183
+ callback(false);
184
+ },
185
+ },
186
+ };
187
+ </script>
188
+
189
+ <style lang="scss" scoped>
190
+ .ri-wrap {
191
+ width: 100%;
192
+ }
193
+
194
+ .ri-editor-wrap {
195
+ border: 1px solid #e0d8ff;
196
+ border-radius: 8px;
197
+ overflow: hidden;
198
+ transition: border-color 0.2s;
199
+ background: #fff;
200
+
201
+ &.ri-editor-focus {
202
+ border-color: #6040e0;
203
+ }
204
+ }
205
+
206
+ .ri-editor {
207
+ background: transparent;
208
+ font-size: 13px;
209
+ color: #333;
210
+ }
211
+
212
+ .ri-toolbar {
213
+ display: flex;
214
+ justify-content: flex-end;
215
+ margin-top: 4px;
216
+ }
217
+
218
+ .ri-formula-btn {
219
+ display: inline-flex;
220
+ align-items: center;
221
+ gap: 3px;
222
+ font-size: 12px;
223
+ color: #6040e0;
224
+ cursor: pointer;
225
+ user-select: none;
226
+ font-weight: bold;
227
+ padding: 2px 6px;
228
+ border-radius: 4px;
229
+ transition: background 0.2s;
230
+
231
+ &:hover {
232
+ background: rgba(96, 64, 224, 0.08);
233
+ }
234
+ }
235
+
236
+ .ri-fx-img {
237
+ width: 16px;
238
+ height: 16px;
239
+ object-fit: contain;
240
+ vertical-align: middle;
241
+ }
242
+
243
+ .ri-formula-iframe {
244
+ width: 782px;
245
+ height: 420px;
246
+ border: none;
247
+ outline: none;
248
+ }
249
+
250
+ .ri-formula-save {
251
+ position: absolute;
252
+ right: 24px;
253
+ bottom: 10px;
254
+ }
255
+
256
+ .ri-formula-container {
257
+ position: relative;
258
+ padding: 24px;
259
+ border-radius: 16px;
260
+ background: linear-gradient(
261
+ 103.5deg,
262
+ rgba(255, 238, 238, 1) 0%,
263
+ rgba(255, 255, 255, 1) 29%,
264
+ rgba(255, 255, 255, 1) 71%,
265
+ rgba(204, 238, 255, 1) 100%
266
+ );
267
+ }
268
+ </style>
269
+
270
+ <style lang="scss">
271
+ .ri-formula-popover {
272
+ padding: 2px;
273
+ border-radius: 16px;
274
+ z-index: 3000 !important;
275
+ }
276
+
277
+ /* 覆盖 wangeditor 默认样式,使其适配字段高度 */
278
+ .ri-editor-wrap {
279
+ .w-e-text-container {
280
+ background: transparent !important;
281
+
282
+ p {
283
+ span {
284
+ background-color: transparent !important;
285
+ }
286
+ }
287
+ }
288
+
289
+ .w-e-text-placeholder {
290
+ font-size: 13px;
291
+ color: #bbb;
292
+ }
293
+
294
+ /* 隐藏工具栏(simple 模式无工具栏,仅保留悬浮栏) */
295
+ .w-e-toolbar {
296
+ display: none !important;
297
+ }
298
+ }
299
+ </style>
300
+
301
+ <style src="@wangeditor/editor/dist/css/style.css"></style>
@@ -52,7 +52,8 @@
52
52
  <read-over :exercises-data="activeItem"
53
53
  :analyze-data="analyzeData"
54
54
  @on-reanswer="onReanswer"
55
- @on-noty-apply="notyApply"/>
55
+ @on-noty-apply="notyApply"
56
+ @on-edit="onEditAnalyze"/>
56
57
  <div class="member-table" v-if="stretch">
57
58
  <member-table :check-data="showTableList"
58
59
  :show-data="tabList"
@@ -68,7 +69,7 @@
68
69
  import ReadOver from './read-over.vue';
69
70
  import { getUserInfo } from '../utils/config';
70
71
  // import {generateReview, registerSse, criticismApply, reanswerReview} from '../api/index';
71
- import { generateReview, loopPoll, criticismApply, reanswerReview } from '../api/index';
72
+ import { generateReview, loopPoll, criticismApply, reanswerReview, analysisSave } from '../api/index';
72
73
  import Cookies from "js-cookie";
73
74
  import TabFilter from './tab-filter.vue';
74
75
  import MemberTable from './member-table.vue';
@@ -307,6 +308,20 @@ export default {
307
308
  if (!this.listData || this.listData.length < 1) {
308
309
  throw new Error('list-data 不能为空或者长度不能为0');
309
310
  }
311
+ },
312
+ async onEditAnalyze(data) {
313
+ this.$set(this.replyCache, this.activeItem.id, data);
314
+ this.analyzeData = data;
315
+ try {
316
+ await analysisSave({
317
+ id: data.id,
318
+ analysis: JSON.stringify(data.jsonContent),
319
+ score: data.score,
320
+ });
321
+ this.$message.success('保存成功');
322
+ } catch (e) {
323
+ this.$message.error('保存失败,请重试');
324
+ }
310
325
  }
311
326
  }
312
327
  }