wlzboy
2026-01-24 2f09efc660bf2cc94cbc5291ad25ca06fc9bdadf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
<template>
  <div class="app-container">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>OCR图像识别测试</span>
      </div>
 
      <!-- 功能说明 -->
      <el-alert
        title="功能说明"
        type="info"
        :closable="false"
        style="margin-bottom: 20px"
      >
        <div>
          本页面用于测试阿里云OCR、百度OCR和腾讯云OCR图像识别功能。支持通用文字识别、发票识别、身份证识别、手写体识别等。<br/>
          <strong>支持格式:</strong>JPG、PNG、BMP等常见图片格式;<strong>文件大小:</strong>不超过4MB
        </div>
      </el-alert>
 
      <!-- 识别类型选择 -->
      <el-form :inline="true" style="margin-bottom: 20px">
        <el-form-item label="识别类型">
          <el-select v-model="recognizeType" placeholder="请选择识别类型" style="width: 200px">
            <el-option label="通用文字识别" value="General" />
            <el-option label="发票识别" value="Invoice" />
            <el-option label="身份证识别" value="IdCard" />
            <el-option label="手写体识别" value="HandWriting" />
          </el-select>
        </el-form-item>
        <el-form-item label="OCR服务">
          <el-select v-model="provider" placeholder="请选择OCR服务提供商" style="width: 200px">
            <el-option label="阿里云OCR" value="ali" />
            <el-option label="百度OCR" value="baidu" />
            <el-option label="腾讯云OCR" value="tencent" />
          </el-select>
        </el-form-item>
        <el-form-item label="提取字段">
          <el-input
            v-if="provider === 'tencent' && recognizeType === 'HandWriting'"
            v-model="itemNames"
            placeholder="请输入需要提取的字段,用逗号分隔"
            style="width: 200px"
            clearable
          />
        </el-form-item>
      </el-form>
 
      <!-- 图片上传区域 -->
      <el-row :gutter="20">
        <el-col :span="12">
          <el-card shadow="hover">
            <div slot="header">
              <span>图片上传</span>
            </div>
            
            <el-upload
              ref="upload"
              class="upload-demo"
              drag
              action="#"
              :auto-upload="false"
              :on-change="handleFileChange"
              :limit="1"
              :file-list="fileList"
              accept="image/*"
            >
              <i class="el-icon-upload"></i>
              <div class="el-upload__text">将图片拖到此处,或<em>点击上传</em></div>
              <div class="el-upload__tip" slot="tip">
                支持JPG、PNG、BMP格式,文件不超过4MB
              </div>
            </el-upload>
 
            <div style="margin-top: 20px; text-align: center">
              <el-button
                type="primary"
                :loading="recognizing"
                :disabled="!fileList.length"
                @click="handleRecognize"
              >
                <i class="el-icon-view"></i> 开始识别
              </el-button>
              <el-button @click="handleClear">
                <i class="el-icon-delete"></i> 清空
              </el-button>
            </div>
 
            <!-- 图片预览 -->
            <div v-if="imagePreview" style="margin-top: 20px">
              <el-divider>图片预览</el-divider>
              <div style="text-align: center">
                <el-image
                  :src="imagePreview"
                  fit="contain"
                  style="max-width: 100%; max-height: 400px"
                  :preview-src-list="[imagePreview]"
                />
              </div>
            </div>
          </el-card>
        </el-col>
 
        <!-- 识别结果区域 -->
        <el-col :span="12">
          <el-card shadow="hover" style="min-height: 500px">
            <div slot="header">
              <span>识别结果</span>
              <el-button
                v-if="ocrResult"
                style="float: right; padding: 3px 0"
                type="text"
                @click="handleCopyResult"
              >
                <i class="el-icon-document-copy"></i> 复制结果
              </el-button>
            </div>
 
            <!-- 加载中 -->
            <div v-if="recognizing" style="text-align: center; padding: 50px 0">
              <i class="el-icon-loading" style="font-size: 40px; color: #409EFF"></i>
              <p style="margin-top: 20px; color: #909399">正在识别中,请稍候...({{ provider === 'ali' ? '阿里云' : provider === 'baidu' ? '百度' : '腾讯云' }})</p>
            </div>
 
            <!-- 识别成功 -->
            <div v-else-if="ocrResult && ocrResult.success">
              <el-alert
                title="识别成功"
                type="success"
                :closable="false"
                style="margin-bottom: 15px"
              >
                <div>服务提供商: {{ provider === 'ali' ? '阿里云OCR' : provider === 'baidu' ? '百度OCR' : '腾讯云OCR' }}</div>
              </el-alert>
 
              <!-- 提取的字段信息 -->
              <div v-if="extractedFields && Object.keys(extractedFields).length > 0">
                <el-descriptions title="提取字段" :column="1" border>
                  <el-descriptions-item
                    v-for="(value, key) in extractedFields"
                    :key="key"
                    :label="getFieldLabel(key)"
                  >
                    {{ value }}
                  </el-descriptions-item>
                </el-descriptions>
                <el-divider />
              </div>
 
              <!-- 完整识别内容 -->
              <div>
                <h4>完整识别内容:</h4>
                <el-input
                  type="textarea"
                  :value="getFullContent(ocrResult)"
                  :autosize="{ minRows: 10, maxRows: 20 }"
                  readonly
                  style="margin-top: 10px"
                />
              </div>
 
              <!-- 原始JSON数据 -->
              <el-collapse style="margin-top: 20px">
                <el-collapse-item title="查看原始JSON数据" name="json">
                  <pre style="background: #f5f7fa; padding: 15px; border-radius: 4px; max-height: 400px; overflow: auto">{{ JSON.stringify(ocrResult, null, 2) }}</pre>
                </el-collapse-item>
              </el-collapse>
            </div>
 
            <!-- 识别失败 -->
            <div v-else-if="ocrResult && !ocrResult.success">
              <el-alert
                title="识别失败"
                :description="ocrResult.error || '未知错误'"
                type="error"
                :closable="false"
              >
                <div>服务提供商: {{ provider === 'ali' ? '阿里云OCR' : provider === 'baidu' ? '百度OCR' : '腾讯云OCR' }}</div>
              </el-alert>
              <div v-if="ocrResult.detail" style="margin-top: 15px">
                <el-tag type="warning">{{ ocrResult.detail }}</el-tag>
              </div>
            </div>
 
            <!-- 未开始识别 -->
            <div v-else style="text-align: center; padding: 50px 0; color: #909399">
              <i class="el-icon-picture-outline" style="font-size: 60px"></i>
              <p style="margin-top: 20px">请上传图片并点击"开始识别"按钮</p>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </el-card>
  </div>
</template>
 
<script>
import { recognizeImage, extractFields } from "@/api/system/ocr";
 
export default {
  name: "OCRTest",
  data() {
    return {
      // 识别类型
      recognizeType: "General",
      // OCR服务提供商
      provider: "ali",
      // 腾讯云OCR提取字段
      itemNames: "患者姓名,性别,年龄,身份证号,诊断,需支付转运费用,行程,开始时间,结束时间,家属签名",
      // 文件列表
      fileList: [],
      // 当前文件
      currentFile: null,
      // 图片预览
      imagePreview: null,
      // 识别中
      recognizing: false,
      // OCR识别结果
      ocrResult: null,
      // 提取的字段
      extractedFields: null
    };
  },
  methods: {
    /** 文件选择变化 */
    handleFileChange(file, fileList) {
      // 限制只能上传一个文件
      if (fileList.length > 1) {
        fileList.splice(0, 1);
      }
      
      this.fileList = fileList;
      this.currentFile = file.raw;
      
      // 生成图片预览
      const reader = new FileReader();
      reader.onload = (e) => {
        this.imagePreview = e.target.result;
      };
      reader.readAsDataURL(file.raw);
      
      // 清空之前的识别结果
      this.ocrResult = null;
      this.extractedFields = null;
    },
 
    /** 开始识别 */
    handleRecognize() {
      if (!this.currentFile) {
        this.$modal.msgWarning("请先上传图片");
        return;
      }
 
      // 检查文件大小(4MB)
      const maxSize = 4 * 1024 * 1024;
      if (this.currentFile.size > maxSize) {
        this.$modal.msgError("图片大小不能超过4MB");
        return;
      }
 
      this.recognizing = true;
      this.ocrResult = null;
      this.extractedFields = null;
 
      // 构建FormData
      const formData = new FormData();
      formData.append("file", this.currentFile);
      formData.append("type", this.recognizeType);
      formData.append("provider", this.provider);
      
      // 如果是腾讯云OCR手写体识别,则添加itemNames参数
      if (this.provider === 'tencent' && this.recognizeType === 'HandWriting' && this.itemNames) {
        const itemNamesArray = this.itemNames.split(',').map(item => item.trim()).filter(item => item);
        itemNamesArray.forEach((itemName, index) => {
          formData.append(`itemNames[${index}]`, itemName);
        });
      }
 
      // 调用OCR识别接口
      recognizeImage(formData).then(response => {
        this.ocrResult = response.data.ocrResult;
        
        // 自动提取字段
        if (this.ocrResult.success) {
          extractFields(this.ocrResult).then(res => {
            this.extractedFields = res.data;
          }).catch(() => {
            // 提取失败不影响主流程
          });
        }
        
        this.recognizing = false;
      }).catch(error => {
        this.$modal.msgError("OCR识别失败: " + (error.message || "未知错误"));
        this.recognizing = false;
      });
    },
 
    /** 清空 */
    handleClear() {
      this.fileList = [];
      this.currentFile = null;
      this.imagePreview = null;
      this.ocrResult = null;
      this.extractedFields = null;
      this.$refs.upload.clearFiles();
    },
 
    /** 复制识别结果 */
    handleCopyResult() {
      const content = this.getFullContent(this.ocrResult);
      this.copyToClipboard(content);
      this.$modal.msgSuccess("复制成功");
    },
 
    /** 复制到剪贴板 */
    copyToClipboard(text) {
      const textarea = document.createElement("textarea");
      textarea.value = text;
      document.body.appendChild(textarea);
      textarea.select();
      document.execCommand("copy");
      document.body.removeChild(textarea);
    },
 
    /** 获取完整识别内容 */
    getFullContent(ocrResult) {
      if (!ocrResult) return "";
      
      if (ocrResult.content) {
        return ocrResult.content;
      }
      
      // 如果有prism_wordsInfo,拼接所有文字
      if (ocrResult.prism_wordsInfo && Array.isArray(ocrResult.prism_wordsInfo)) {
        return ocrResult.prism_wordsInfo.map(item => item.word).join("\n");
      }
      
      return JSON.stringify(ocrResult, null, 2);
    },
 
    /** 获取字段标签 */
    getFieldLabel(key) {
      const labelMap = {
        totalAmount: "总金额",
        date: "日期",
        remark: "备注",
        fullText: "全文",
        error: "错误信息"
      };
      return labelMap[key] || key;
    }
  }
};
</script>
 
<style scoped>
.box-card {
  margin-bottom: 20px;
}
 
.upload-demo {
  width: 100%;
}
 
.el-upload-dragger {
  width: 100%;
}
 
pre {
  font-family: 'Courier New', Courier, monospace;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-wrap: break-word;
}
 
.el-descriptions {
  margin-top: 10px;
}
 
h4 {
  margin: 15px 0 10px 0;
  color: #303133;
}
</style>