@zscreate/zhxy-app-component 1.0.372 → 1.0.374

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,449 @@
1
+ <template>
2
+ <u2-popup
3
+ :show="visible"
4
+ mode="center"
5
+ :round="20"
6
+ :closeable="!loading"
7
+ @close="handleCancel"
8
+ >
9
+ <view class="ai-fill-form">
10
+ <!-- 标题 -->
11
+ <view class="modal-header">
12
+ <text class="modal-title">AI填表</text>
13
+ </view>
14
+
15
+ <!-- 内容区域 -->
16
+ <view class="modal-content">
17
+ <!-- 加载状态 -->
18
+ <view v-if="loading" class="loading-container">
19
+ <u2-loading-icon mode="circle" :color="themeConfig.color || '#2979ff'"></u2-loading-icon>
20
+ <text class="loading-text">{{ tips }}</text>
21
+ </view>
22
+
23
+ <!-- 表单内容 -->
24
+ <view v-else>
25
+ <view class="form-item">
26
+ <view class="label">请输入或粘贴内容:</view>
27
+ <u2-textarea
28
+ v-model="contentText"
29
+ placeholder="请输入或粘贴需要识别的内容,例如:张三 男 合肥大学"
30
+ :disabled="loading"
31
+ height="200"
32
+ count
33
+ ></u2-textarea>
34
+ </view>
35
+
36
+ <!-- 进度条 -->
37
+ <view class="progress-info" v-if="recognizeProgress.total > 0">
38
+ <u2-line-progress
39
+ :percentage="progressPercent"
40
+ :activeColor="themeConfig.color || '#2979ff'"
41
+ height="12"
42
+ ></u2-line-progress>
43
+ <view class="progress-text">
44
+ {{ recognizeProgress.current }}/{{ recognizeProgress.total }}
45
+ </view>
46
+ </view>
47
+
48
+ <!-- 识别结果 -->
49
+ <view class="result-list" v-if="resultList.length > 0">
50
+ <view class="result-title">识别结果:</view>
51
+ <scroll-view scroll-y class="result-scroll">
52
+ <view class="result-item" v-for="(item, index) in resultList" :key="index">
53
+ <text class="field-name">{{ item.fieldName }}:</text>
54
+ <text class="field-value" :class="{ 'empty-value': item.value === undefined }">
55
+ {{ item.value === undefined ? '未识别成功' : item.value }}
56
+ </text>
57
+ </view>
58
+ </scroll-view>
59
+ </view>
60
+ </view>
61
+ </view>
62
+
63
+ <!-- 底部按钮 -->
64
+ <view class="footer-btns">
65
+ <u2-button
66
+ text="取消"
67
+ @click="handleCancel"
68
+ :disabled="loading"
69
+ :customStyle="{ flex: 1, marginRight: '20rpx',backgroundColor: '#ccc'}"
70
+ ></u2-button>
71
+ <u2-button
72
+ type="primary"
73
+ text="开始识别"
74
+ @click="startRecognize"
75
+ :loading="loading"
76
+ :disabled="!contentText.trim()"
77
+ :customStyle="{
78
+ flex: 1,
79
+ marginRight: resultList.length > 0 ? '20rpx' : '0',
80
+ backgroundColor: themeConfig.color || '#2979ff',
81
+ borderColor: themeConfig.color || '#2979ff',
82
+ color: '#fff'
83
+ }"
84
+ ></u2-button>
85
+ <u2-button
86
+ v-if="resultList.length > 0 && hasSuccessResult"
87
+ type="primary"
88
+ text="确认填入"
89
+ @click="handleOk"
90
+ :disabled="loading"
91
+ :customStyle="{
92
+ flex: 1,
93
+ backgroundColor: themeConfig.color || '#2979ff',
94
+ borderColor: themeConfig.color || '#2979ff',
95
+ color: '#fff',
96
+ }"
97
+ ></u2-button>
98
+ </view>
99
+ </view>
100
+ </u2-popup>
101
+ </template>
102
+
103
+ <script>
104
+ export default {
105
+ name: "AIAutoFillForm",
106
+ components: {},
107
+
108
+ data() {
109
+ return {
110
+ visible: false,
111
+ loading: false,
112
+ tips: "",
113
+ formData: {}, // 表单配置
114
+ models: {}, // 表单的值
115
+ formList: [], // 需要匹配得表单组件
116
+ contentText: '', // 用户输入的内容
117
+ recognizeProgress: {
118
+ current: 0,
119
+ total: 0,
120
+ currentField: ''
121
+ },
122
+ resultList: [], // 识别结果列表
123
+ needRecognizeList: [], // 需要识别的字段列表
124
+ };
125
+ },
126
+
127
+ mounted() {},
128
+ computed: {
129
+ themeConfig() {
130
+ return this.$store.getters["theme/themeConfig"] || {};
131
+ },
132
+ progressPercent() {
133
+ if (this.recognizeProgress.total === 0) return 0;
134
+ return Math.round((this.recognizeProgress.current / this.recognizeProgress.total) * 100);
135
+ },
136
+ // 是否有识别成功的数据
137
+ hasSuccessResult() {
138
+ return this.resultList.some(item => item.value !== undefined);
139
+ }
140
+ },
141
+
142
+ methods: {
143
+ init(formData, models) {
144
+ console.log(formData, models);
145
+ this.formList = []
146
+ this.formData = formData; // 表单配置
147
+ this.formData.list.forEach(item => {
148
+ if(['grid'].includes(item.type)) { //栅格
149
+ item.columns.forEach(el => {
150
+ if (el.list && el.list[0]) {
151
+ this.formList.push(el.list[0])
152
+ }
153
+ })
154
+ } else if (['input', 'textarea', 'number', 'date', 'time'].includes(item.type)) { //输入框
155
+ this.formList.push(item)
156
+ }
157
+ })
158
+ console.log('formList:', this.formList);
159
+
160
+ this.models = models; // 表单的值
161
+
162
+ // 重置状态
163
+ this.contentText = '';
164
+ this.recognizeProgress = { current: 0, total: 0, currentField: '' };
165
+ this.resultList = [];
166
+ this.needRecognizeList = [];
167
+
168
+ this.visible = true;
169
+ },
170
+
171
+ handleCancel() {
172
+ this.visible = false;
173
+ this.contentText = '';
174
+ this.recognizeProgress = { current: 0, total: 0, currentField: '' };
175
+ this.resultList = [];
176
+ this.needRecognizeList = [];
177
+ },
178
+
179
+ // 开始识别
180
+ async startRecognize() {
181
+ if (!this.contentText.trim()) {
182
+ uni.showToast({
183
+ title: '请先输入或粘贴需要识别的内容',
184
+ icon: 'none',
185
+ duration: 2000
186
+ });
187
+ return;
188
+ }
189
+
190
+ // 筛选出需要识别的字段(值为空的字段)
191
+ this.needRecognizeList = this.formList.filter(item => {
192
+ const modelValue = this.models[item.model];
193
+ // 判断值是否为空
194
+ return !modelValue || modelValue === '' ||
195
+ (Array.isArray(modelValue) && modelValue.length === 0);
196
+ });
197
+
198
+ if (this.needRecognizeList.length === 0) {
199
+ uni.showToast({
200
+ title: '所有字段都已有值,无需识别',
201
+ icon: 'none',
202
+ duration: 2000
203
+ });
204
+ return;
205
+ }
206
+
207
+ console.log('需要识别的字段:', this.needRecognizeList);
208
+
209
+ // 初始化进度
210
+ this.recognizeProgress = {
211
+ current: 0,
212
+ total: this.needRecognizeList.length,
213
+ currentField: ''
214
+ };
215
+ this.resultList = [];
216
+ this.loading = true;
217
+
218
+ try {
219
+ // 逐个调用接口识别
220
+ for (let i = 0; i < this.needRecognizeList.length; i++) {
221
+ const field = this.needRecognizeList[i];
222
+
223
+ // 更新进度
224
+ this.recognizeProgress.current = i + 1;
225
+ this.recognizeProgress.currentField = field.name;
226
+ this.tips = `正在识别:${field.name} (${i + 1}/${this.needRecognizeList.length})`;
227
+
228
+ try {
229
+ // 调用识别接口
230
+ const result = await this.recognizeField(field);
231
+
232
+ // 保存识别结果
233
+ this.resultList.push({
234
+ model: field.model,
235
+ fieldName: field.name,
236
+ value: result
237
+ });
238
+
239
+ } catch (error) {
240
+ console.error(`识别字段 ${field.name} 失败:`, error);
241
+ // 识别失败也记录结果
242
+ this.resultList.push({
243
+ model: field.model,
244
+ fieldName: field.name,
245
+ value: undefined
246
+ });
247
+ }
248
+ }
249
+
250
+ uni.showToast({
251
+ title: '识别完成',
252
+ icon: 'success',
253
+ duration: 2000
254
+ });
255
+
256
+ } catch (error) {
257
+ console.error('识别过程出错:', error);
258
+ uni.showToast({
259
+ title: '识别过程出错,请重试',
260
+ icon: 'none',
261
+ duration: 2000
262
+ });
263
+ } finally {
264
+ this.loading = false;
265
+ this.tips = '';
266
+ }
267
+ },
268
+
269
+ // 调用接口识别单个字段
270
+ async recognizeField(field) {
271
+ const params = {
272
+ content: this.contentText.trim(),
273
+ keyword: field.name
274
+ };
275
+
276
+ try {
277
+ const res = await this.$u.post('/formApi/getDifyWorkFlowData', params);
278
+
279
+ if (res.success) {
280
+ const result = res.result || res.data || '';
281
+ // 处理返回值为字符串 "null" 的情况
282
+ if (result === 'null' || result === null || result === '') {
283
+ return undefined; // 返回 undefined 表示未识别成功
284
+ }
285
+ return result;
286
+ } else {
287
+ console.warn(`识别 ${field.name} 失败:`, res.message);
288
+ return undefined;
289
+ }
290
+ } catch (error) {
291
+ console.error(`接口调用失败:`, error);
292
+ throw error;
293
+ }
294
+ },
295
+
296
+ handleOk() {
297
+ debugger
298
+ if (this.resultList.length === 0) {
299
+ uni.showToast({
300
+ title: '请先进行识别',
301
+ icon: 'none',
302
+ duration: 2000
303
+ });
304
+ return;
305
+ }
306
+
307
+ // 将识别结果填入表单
308
+ const updatedModels = { ...this.models };
309
+
310
+ this.resultList.forEach(item => {
311
+ // 只填入有效值(非 undefined)
312
+ if (item.value !== undefined) {
313
+ updatedModels[item.model] = item.value;
314
+ } else {
315
+ // 未识别成功的字段,设置为 undefined
316
+ updatedModels[item.model] = undefined;
317
+ }
318
+ });
319
+
320
+ console.log('填入的数据:', updatedModels);
321
+ this.$emit('callback', updatedModels);
322
+ uni.showToast({
323
+ title: 'AI填表成功',
324
+ icon: 'success',
325
+ duration: 2000
326
+ });
327
+ this.handleCancel();
328
+ },
329
+ },
330
+ };
331
+ </script>
332
+ <style lang="less" scoped>
333
+ .ai-fill-form {
334
+ width: 650rpx;
335
+ background: #ffffff;
336
+ border-radius: 20rpx;
337
+ overflow: hidden;
338
+
339
+ .modal-header {
340
+ padding: 10rpx 32rpx 10rpx;
341
+ border-bottom: 1rpx solid #ebeef5;
342
+ text-align: center;
343
+
344
+ .modal-title {
345
+ font-size: 36rpx;
346
+ font-weight: 600;
347
+ color: #303133;
348
+ text-align: center;
349
+ }
350
+ }
351
+
352
+ .modal-content {
353
+ padding: 32rpx;
354
+ max-height: 800rpx;
355
+ overflow-y: auto;
356
+ }
357
+
358
+ .form-item {
359
+ margin-bottom: 32rpx;
360
+
361
+ .label {
362
+ font-size: 28rpx;
363
+ color: #303133;
364
+ margin-bottom: 16rpx;
365
+ font-weight: 500;
366
+ }
367
+ }
368
+
369
+ .progress-info {
370
+ margin-bottom: 32rpx;
371
+
372
+ .progress-text {
373
+ margin-top: 16rpx;
374
+ font-size: 24rpx;
375
+ color: #606266;
376
+ text-align: center;
377
+ }
378
+ }
379
+
380
+ .loading-container {
381
+ display: flex;
382
+ flex-direction: column;
383
+ align-items: center;
384
+ justify-content: center;
385
+ padding: 80rpx 0;
386
+
387
+ .loading-text {
388
+ margin-top: 24rpx;
389
+ font-size: 28rpx;
390
+ color: #606266;
391
+ }
392
+ }
393
+
394
+ .result-list {
395
+ margin-bottom: 32rpx;
396
+ padding: 24rpx;
397
+ background: #f5f7fa;
398
+ border-radius: 12rpx;
399
+
400
+ .result-title {
401
+ font-size: 28rpx;
402
+ font-weight: 500;
403
+ color: #303133;
404
+ margin-bottom: 20rpx;
405
+ }
406
+
407
+ .result-scroll {
408
+ max-height: 400rpx;
409
+ }
410
+
411
+ .result-item {
412
+ padding: 16rpx 0;
413
+ border-bottom: 1rpx dashed #dcdfe6;
414
+ font-size: 26rpx;
415
+
416
+ &:last-child {
417
+ border-bottom: none;
418
+ }
419
+
420
+ .field-name {
421
+ color: #606266;
422
+ margin-right: 12rpx;
423
+ }
424
+
425
+ .field-value {
426
+ color: #2979ff;
427
+ font-weight: 500;
428
+
429
+ &.empty-value {
430
+ color: #909399;
431
+ font-style: italic;
432
+ }
433
+ }
434
+ }
435
+ }
436
+
437
+ .footer-btns {
438
+ display: flex;
439
+ padding: 24rpx 32rpx;
440
+ padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
441
+ border-top: 1rpx solid #ebeef5;
442
+ background: #ffffff;
443
+ }
444
+ }
445
+ ::v-deep .u2-popup__content__close {
446
+ right: 20rpx !important;
447
+ top: 20rpx !important;
448
+ }
449
+ </style>
@@ -306,6 +306,7 @@
306
306
  <unploadFile :widget="widget" ref="imgUpload" :action="getUploadFileUrl(widget)" @filePost="filePost" @fileDelete="fileDelete"
307
307
  :defaultImg="dataModel"></unploadFile>
308
308
  </view>
309
+ <view style="color: rgb(0, 122, 255);margin-top: 0;margin-left: 30rpx;" @click="batchDownload" v-if="dataModel && dataModel.length && widget.options.downLoadBatch && models.businessFormDataId">批量下载</view>
309
310
  </view>
310
311
 
311
312
  <!-- fileupload -->
@@ -320,6 +321,7 @@
320
321
  @fileDelete="fileDelete" :defaultFile="dataModel" :widget="widget" style="width: 100%;">
321
322
  </l-file>
322
323
  </view>
324
+ <view style="color: rgb(0, 122, 255);margin-top: 0;margin-left: 30rpx;" @click="batchDownload" v-if="dataModel && dataModel.length && widget.options.downLoadBatch && models.businessFormDataId">批量下载</view>
323
325
  </view>
324
326
  <!-- conferenceRoom(会议室) -->
325
327
  <view v-else-if="widget.type === 'conferenceRoom'" class="evan-form-item-container"
@@ -947,6 +949,19 @@ export default {
947
949
  uni.$off(this.widget.model);
948
950
  },
949
951
  methods: {
952
+ batchDownload() {
953
+ let params = {
954
+ fileList: this.models[this.widget.model],
955
+ businessFormDataId: this.models.businessFormDataId,
956
+ }
957
+ debugger
958
+ this.$u.post('/appApi/downLoadAttachment', params).then(res => {
959
+ if(res.success && res.result) {
960
+ let name = res.result.split('/')[res.result.split('/').length - 1]
961
+ downloadFile(this.downLoadUrl, { path: res.result, name })
962
+ }
963
+ })
964
+ },
950
965
  textareaInputChange(e) {
951
966
  this.textareaValue = e.detail.value
952
967
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zscreate/zhxy-app-component",
3
- "version": "1.0.372",
3
+ "version": "1.0.374",
4
4
  "private": false,
5
5
  "description": "zhxy-app-component",
6
6
  "main": "index.js",