af-mobile-client-vue3 1.6.45 → 1.6.47

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 (33) hide show
  1. package/package.json +1 -1
  2. package/src/components/core/ImageUploader/index.vue +5 -1
  3. package/src/components/data/FilePreview/index.vue +76 -9
  4. package/src/components/data/XForm/index.vue +2 -1
  5. package/src/components/data/XFormItem/index.vue +2 -1
  6. package/src/components/data/XReportGrid/XReportDemo.vue +33 -33
  7. package/src/components/data/XReportGrid/print.js +184 -184
  8. package/src/components/data/step/person-select.vue +168 -168
  9. package/src/stores/modules/safecheckStore.ts +47 -47
  10. package/src/stores/modules/step.ts +88 -88
  11. package/src/utils/PhotoClean.ts +21 -21
  12. package/src/utils/appBackManager.ts +23 -23
  13. package/src/utils/fileType.ts +11 -5
  14. package/src/utils/safeBack.ts +38 -38
  15. package/src/utils/timeUtil.ts +27 -27
  16. package/src/views/SafeInspection/SecurityCertificate/AddDevice/index.vue +1 -0
  17. package/src/views/SafeInspection/SecurityCertificate/AddDevice/types/device.ts +2 -0
  18. package/src/views/SafeInspection/SecurityCertificate/OverallHiddenDangers/index.vue +2 -1
  19. package/src/views/SafeInspection/SecurityCertificate/contractSign/index.vue +2 -1
  20. package/src/views/SafeInspection/SecurityCertificate/index.vue +14 -11
  21. package/src/views/SafeInspection/SecurityCertificate/photoAiRecognition/components/PhotoCaptureCard.vue +3 -2
  22. package/src/views/SafeInspection/SecurityCertificate/photoAiRecognition/index.vue +2 -1
  23. package/src/views/SafeInspection/SecurityCertificate/photoSignature/index.vue +2 -1
  24. package/src/views/SafeInspection/SecurityCertificate/photoSignature/slots/QinHuaSignature.vue +16 -11
  25. package/src/views/SafeInspection/SecurityCertificate/slots/GasDevice.vue +1 -0
  26. package/src/views/SafeInspection/SecurityCertificate/userInfo/index.vue +6 -1
  27. package/src/views/SafeInspection/SecurityFormItem/CameraView/index.vue +3 -3
  28. package/src/views/SafeInspection/SecurityFormItem/FormItem.vue +2 -1
  29. package/src/views/SafeInspection/SecurityFormItem/index.vue +4 -1
  30. package/src/views/component/FilePreviewView/index.vue +31 -31
  31. package/src/views/component/StepView/index.vue +1 -1
  32. package/src/views/component/XFormView/index.vue +2 -2
  33. package/vite.config.ts +1 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "af-mobile-client-vue3",
3
3
  "type": "module",
4
- "version": "1.6.45",
4
+ "version": "1.6.47",
5
5
  "packageManager": "pnpm@10.13.1",
6
6
  "description": "Vue + Vite component lib",
7
7
  "engines": {
@@ -35,7 +35,7 @@ const props = defineProps({
35
35
  readonly: { type: Boolean, default: false },
36
36
  isAsyncUpload: { type: Boolean, default: false },
37
37
  })
38
- const emit = defineEmits(['updateFileList', 'updateAllFileList'])
38
+ const emit = defineEmits(['updateFileList', 'updateAllFileList', 'photoQualityChange'])
39
39
 
40
40
  const imageList = ref<Array<any>>(props.imageList ?? [])
41
41
 
@@ -187,6 +187,9 @@ function triggerCamera() {
187
187
  rePhotoCheck(result.data)
188
188
  }
189
189
  else if (result.status === 'error') {
190
+ if (result?.message && result.message.startsWith('图片质量检测失败')) {
191
+ emit('photoQualityChange', 'quality-failed')
192
+ }
190
193
  const env = detectEnvironment()
191
194
  // App 环境下弹窗提示错误
192
195
  if (env.isApp) {
@@ -230,6 +233,7 @@ function rePhotoCheck(photoData: any) {
230
233
  if (result && result.status === 'success') {
231
234
  const checkRePhotoResult = result.data
232
235
  if (checkRePhotoResult.is_rephoto === true || checkRePhotoResult.is_rephoto === 'true') {
236
+ emit('photoQualityChange', 'rephoto-detected')
233
237
  console.warn(`检测到当前图片属于翻拍照片\n请上传合法图片!`)
234
238
  showFailToast({
235
239
  message: `当前图片属于翻拍照片\n请上传合法图片!`,
@@ -40,6 +40,7 @@ const fileSource = shallowRef<string | ArrayBuffer>('')
40
40
  const textContent = ref('')
41
41
  const imageSrc = ref('')
42
42
  const videoSrc = ref('')
43
+ const audioSrc = ref('')
43
44
  const openUrl = ref('')
44
45
  const downloadName = ref('')
45
46
  const loading = ref(false)
@@ -66,24 +67,36 @@ async function init(options: FilePreviewInitOptions) {
66
67
  fileSource.value = ''
67
68
  imageSrc.value = ''
68
69
  videoSrc.value = ''
70
+ audioSrc.value = ''
69
71
 
70
72
  try {
71
73
  switch (previewKind.value) {
72
74
  case 'image':
73
75
  imageSrc.value = openUrl.value
74
76
  break
77
+
75
78
  case 'video':
76
79
  videoSrc.value = openUrl.value
77
80
  break
81
+
82
+ case 'audio':
83
+ audioSrc.value = openUrl.value
84
+ break
85
+
78
86
  case 'text':
79
87
  textContent.value = await fetchResourceText(openUrl.value)
80
88
  break
89
+
81
90
  case 'pdf':
82
91
  case 'docx':
92
+ case 'doc':
83
93
  case 'xlsx':
94
+ case 'xls':
84
95
  fileSource.value = await fetchResourceArrayBuffer(openUrl.value)
85
96
  break
86
- default:
97
+
98
+ case 'unsupported':
99
+ // 未知格式,直接用 iframe 尝试打开,无需预加载内容
87
100
  break
88
101
  }
89
102
  }
@@ -95,11 +108,6 @@ async function init(options: FilePreviewInitOptions) {
95
108
  }
96
109
  }
97
110
 
98
- function openExternal() {
99
- if (openUrl.value)
100
- window.open(openUrl.value, '_blank')
101
- }
102
-
103
111
  function handleDownload() {
104
112
  if (!openUrl.value)
105
113
  return
@@ -139,14 +147,16 @@ defineExpose({
139
147
  class="office-preview"
140
148
  @error="onRenderError"
141
149
  />
150
+ <!-- docx / doc 共用同一渲染器 -->
142
151
  <VueOfficeDocx
143
- v-else-if="previewKind === 'docx' && fileSource"
152
+ v-else-if="(previewKind === 'docx' || previewKind === 'doc') && fileSource"
144
153
  :src="fileSource"
145
154
  class="office-preview"
146
155
  @error="onRenderError"
147
156
  />
157
+ <!-- xlsx / xls 共用同一渲染器 -->
148
158
  <VueOfficeExcel
149
- v-else-if="previewKind === 'xlsx' && fileSource"
159
+ v-else-if="(previewKind === 'xlsx' || previewKind === 'xls') && fileSource"
150
160
  :src="fileSource"
151
161
  class="office-preview"
152
162
  @error="onRenderError"
@@ -157,8 +167,26 @@ defineExpose({
157
167
  <div v-else-if="previewKind === 'video'" class="preview-video-wrapper">
158
168
  <video class="preview-video" controls :src="videoSrc" />
159
169
  </div>
170
+ <div v-else-if="previewKind === 'audio'" class="preview-audio-wrapper">
171
+ <audio class="preview-audio" controls :src="audioSrc" />
172
+ </div>
160
173
  <pre v-else-if="previewKind === 'text'" class="preview-text">{{ textContent }}</pre>
161
- <VanEmpty v-else description="暂不支持在线预览该格式">
174
+ <!-- 未知格式:用 iframe 尝试直接打开,系统/浏览器自行决定如何处理 -->
175
+ <div v-else-if="previewKind === 'unsupported'" class="preview-iframe-wrapper">
176
+ <iframe
177
+ :src="openUrl"
178
+ class="preview-iframe"
179
+ sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
180
+ @error="onRenderError"
181
+ />
182
+ <div class="preview-iframe-fallback">
183
+ <span>若文件无法显示,请</span>
184
+ <VanButton size="small" type="primary" plain @click="handleDownload">
185
+ 下载查看
186
+ </VanButton>
187
+ </div>
188
+ </div>
189
+ <VanEmpty v-else description="文件路径异常">
162
190
  <VanButton v-if="openUrl" size="small" type="primary" @click="handleDownload">
163
191
  下载
164
192
  </VanButton>
@@ -232,4 +260,43 @@ defineExpose({
232
260
  line-height: 1.5;
233
261
  color: #333;
234
262
  }
263
+
264
+ .preview-audio-wrapper {
265
+ display: flex;
266
+ align-items: center;
267
+ justify-content: center;
268
+ padding: 32px 16px;
269
+ min-height: 120px;
270
+ }
271
+
272
+ .preview-audio {
273
+ width: 100%;
274
+ max-width: 480px;
275
+ }
276
+
277
+ .preview-iframe-wrapper {
278
+ display: flex;
279
+ flex-direction: column;
280
+ width: 100%;
281
+ height: 100%;
282
+ flex: 1;
283
+ }
284
+
285
+ .preview-iframe {
286
+ width: 100%;
287
+ flex: 1;
288
+ min-height: 200px;
289
+ border: none;
290
+ }
291
+
292
+ .preview-iframe-fallback {
293
+ display: flex;
294
+ align-items: center;
295
+ gap: 8px;
296
+ padding: 8px 12px;
297
+ font-size: 12px;
298
+ color: #999;
299
+ flex-shrink: 0;
300
+ border-top: 1px solid #f0f0f0;
301
+ }
235
302
  </style>
@@ -93,7 +93,7 @@ const props = withDefaults(defineProps<{
93
93
  enableSubmitLoading: false,
94
94
  })
95
95
 
96
- const emits = defineEmits(['onSubmit', 'xFormItemEmitFunc'])
96
+ const emits = defineEmits(['onSubmit', 'xFormItemEmitFunc', 'photoQualityChange'])
97
97
  const userStore = useUserStore()
98
98
 
99
99
  // inject
@@ -763,6 +763,7 @@ defineExpose({ init, form, formGroupName, validate, asyncSubmit, setForm, getFor
763
763
  @set-form="setForm"
764
764
  @x-form-item-emit-func="emitFunc"
765
765
  @validate-error="handleValidateError"
766
+ @photo-quality-change="(type) => emits('photoQualityChange', type)"
766
767
  />
767
768
  <slot name="extraFormItem" />
768
769
  </VanCellGroup>
@@ -89,7 +89,7 @@ const props = withDefaults(defineProps<{
89
89
  inputAlign: undefined,
90
90
  })
91
91
 
92
- const emits = defineEmits(['setForm', 'xFormItemEmitFunc', 'scanCodeOrNfc', 'validateError'])
92
+ const emits = defineEmits(['setForm', 'xFormItemEmitFunc', 'scanCodeOrNfc', 'validateError', 'photoQualityChange'])
93
93
 
94
94
  // 用 defineModel 替代 modelValue/emit
95
95
  const modelData = defineModel<string | number | boolean | any[] | Record<string, any>>()
@@ -1256,6 +1256,7 @@ onBeforeUnmount(() => {
1256
1256
  :service-name="serviceName"
1257
1257
  :is-async-upload="isAsyncUpload"
1258
1258
  @update-file-list="updateFile"
1259
+ @photo-quality-change="(type) => emits('photoQualityChange', type)"
1259
1260
  />
1260
1261
  </template>
1261
1262
  </VanField>
@@ -1,33 +1,33 @@
1
- <script setup lang="ts">
2
- import { onMounted, ref } from 'vue'
3
- import XReport from './XReport.vue'
4
-
5
- const mainRef = ref()
6
-
7
- onMounted(() => {
8
- // 初始化逻辑
9
- })
10
- </script>
11
-
12
- <template>
13
- <div id="test">
14
- <van-card :bordered="false">
15
- <XReport
16
- ref="mainRef"
17
- :use-oss-for-img="false"
18
- config-name="nurseWorkstationCover"
19
- server-name="af-his"
20
- :show-img-in-cell="true"
21
- :display-only="true"
22
- :edit-mode="false"
23
- :show-save-button="false"
24
- :no-padding="true"
25
- :dont-format="true"
26
- />
27
- </van-card>
28
- </div>
29
- </template>
30
-
31
- <style scoped>
32
-
33
- </style>
1
+ <script setup lang="ts">
2
+ import { onMounted, ref } from 'vue'
3
+ import XReport from './XReport.vue'
4
+
5
+ const mainRef = ref()
6
+
7
+ onMounted(() => {
8
+ // 初始化逻辑
9
+ })
10
+ </script>
11
+
12
+ <template>
13
+ <div id="test">
14
+ <van-card :bordered="false">
15
+ <XReport
16
+ ref="mainRef"
17
+ :use-oss-for-img="false"
18
+ config-name="nurseWorkstationCover"
19
+ server-name="af-his"
20
+ :show-img-in-cell="true"
21
+ :display-only="true"
22
+ :edit-mode="false"
23
+ :show-save-button="false"
24
+ :no-padding="true"
25
+ :dont-format="true"
26
+ />
27
+ </van-card>
28
+ </div>
29
+ </template>
30
+
31
+ <style scoped>
32
+
33
+ </style>
@@ -1,184 +1,184 @@
1
- // print.js
2
-
3
- export function printElement(elementToPrint) {
4
- // 创建一个新的浏览器窗口
5
- const printWindow = window.open('', '_blank', 'height=1024,width=768')
6
- // 设置新窗口的文档内容
7
- printWindow.document.write(`
8
- <html>
9
- <head>
10
- <title>Print</title>
11
- <style>
12
- @page {
13
- size: auto;
14
- margin: 0mm;
15
- }
16
- html, body {
17
- margin: 0;
18
- padding: 0;
19
- width: 100%;
20
- height: 100%;
21
- }
22
- #print-container {
23
- display: none
24
- }
25
- .img{
26
- width: 95%;
27
- height: 180px;
28
- object-fit: cover;
29
- }
30
- .reportMain {
31
- text-align: center;
32
- margin: 0 auto;
33
- font-size: 16px;
34
- color: #000;
35
- background-color: #fff;
36
- border-radius: 8px;
37
-
38
- .reportTitle {
39
- font-weight: bold;
40
- }
41
-
42
- .subTitle {
43
- display: flex;
44
- justify-content: space-between;
45
- margin-bottom: 1%;
46
-
47
- .subTitleItems {
48
- max-width: 30%;
49
- }
50
- }
51
-
52
- .inputsDiv {
53
- display: flex;
54
- justify-content: space-between;
55
- .inputsDivItem {
56
- display: flex;
57
- align-items: center;
58
- padding: 0 4px;
59
- white-space: nowrap;
60
- .inputsDivItemLabel {
61
- padding: 0 4px;
62
- }
63
- }
64
- }
65
-
66
- .reportTable {
67
- width: 100%;
68
- border-collapse: collapse;
69
- table-layout:fixed;
70
- word-break:break-all;
71
- text-align: center;
72
- }
73
- }
74
- .reportMainForDisplay {
75
- text-align: center;
76
- margin: 10% auto;
77
- font-size: 16px;
78
- color: #000;
79
- background-color: #fff;
80
- border-radius: 8px;
81
-
82
- .reportTitle {
83
- font-weight: bold;
84
- }
85
-
86
- .subTitle {
87
- display: flex;
88
- justify-content: space-between;
89
-
90
- .subTitleItems {
91
- max-width: 30%;
92
- }
93
- }
94
-
95
- .inputsDiv {
96
- display: flex;
97
- justify-content: space-around;
98
- .inputsDivItem {
99
- display: flex;
100
- align-items: center;
101
- padding: 0 4px;
102
- white-space: nowrap;
103
- .inputsDivItemLabel {
104
- padding: 0 4px;
105
- }
106
- }
107
- }
108
-
109
- .reportTable {
110
- width: 100%;
111
- border-collapse: collapse;
112
- table-layout:fixed;
113
- word-break:break-all;
114
- }
115
- }
116
- .reportMainNoPadding {
117
- text-align: center;
118
- margin: 0 auto;
119
- font-size: 16px;
120
- color: #000;
121
- background-color: #fff;
122
- border-radius: 8px;
123
-
124
- .reportTitle {
125
- font-weight: bold;
126
- }
127
-
128
- .subTitle {
129
- display: flex;
130
- justify-content: space-between;
131
-
132
- .subTitleItems {
133
- max-width: 30%;
134
- }
135
- }
136
-
137
- .inputsDiv {
138
- display: flex;
139
- justify-content: space-between;
140
- .inputsDivItem {
141
- display: flex;
142
- align-items: center;
143
- padding: 0 4px;
144
- white-space: nowrap;
145
- .inputsDivItemLabel {
146
- padding: 0 4px;
147
- }
148
- }
149
- }
150
-
151
- .reportTable {
152
- width: 100%;
153
- border-collapse: collapse;
154
- table-layout:fixed;
155
- word-break:break-all;
156
- }
157
- }
158
- .tools{
159
- position: fixed;
160
- right: 2%;
161
- text-align: right;
162
- width: 60%;
163
- cursor: pointer;
164
- .toolsItem{
165
- width: 15%;
166
- margin-right: 3%;
167
- display: inline-block;
168
- }
169
- }
170
- </style>
171
- </head>
172
- <body>
173
- <!-- 将需要打印的元素内容复制到新窗口中 -->
174
- ${elementToPrint.innerHTML}
175
- </body>
176
- </html>
177
- `)
178
- // 延迟执行打印,以确保新窗口的内容已加载完成
179
- printWindow.document.close() // 关闭文档流,确保内容完全加载
180
- setTimeout(() => {
181
- printWindow.print() // 调用打印方法
182
- printWindow.close()
183
- }, 500) // 延迟500毫秒后执行打印
184
- }
1
+ // print.js
2
+
3
+ export function printElement(elementToPrint) {
4
+ // 创建一个新的浏览器窗口
5
+ const printWindow = window.open('', '_blank', 'height=1024,width=768')
6
+ // 设置新窗口的文档内容
7
+ printWindow.document.write(`
8
+ <html>
9
+ <head>
10
+ <title>Print</title>
11
+ <style>
12
+ @page {
13
+ size: auto;
14
+ margin: 0mm;
15
+ }
16
+ html, body {
17
+ margin: 0;
18
+ padding: 0;
19
+ width: 100%;
20
+ height: 100%;
21
+ }
22
+ #print-container {
23
+ display: none
24
+ }
25
+ .img{
26
+ width: 95%;
27
+ height: 180px;
28
+ object-fit: cover;
29
+ }
30
+ .reportMain {
31
+ text-align: center;
32
+ margin: 0 auto;
33
+ font-size: 16px;
34
+ color: #000;
35
+ background-color: #fff;
36
+ border-radius: 8px;
37
+
38
+ .reportTitle {
39
+ font-weight: bold;
40
+ }
41
+
42
+ .subTitle {
43
+ display: flex;
44
+ justify-content: space-between;
45
+ margin-bottom: 1%;
46
+
47
+ .subTitleItems {
48
+ max-width: 30%;
49
+ }
50
+ }
51
+
52
+ .inputsDiv {
53
+ display: flex;
54
+ justify-content: space-between;
55
+ .inputsDivItem {
56
+ display: flex;
57
+ align-items: center;
58
+ padding: 0 4px;
59
+ white-space: nowrap;
60
+ .inputsDivItemLabel {
61
+ padding: 0 4px;
62
+ }
63
+ }
64
+ }
65
+
66
+ .reportTable {
67
+ width: 100%;
68
+ border-collapse: collapse;
69
+ table-layout:fixed;
70
+ word-break:break-all;
71
+ text-align: center;
72
+ }
73
+ }
74
+ .reportMainForDisplay {
75
+ text-align: center;
76
+ margin: 10% auto;
77
+ font-size: 16px;
78
+ color: #000;
79
+ background-color: #fff;
80
+ border-radius: 8px;
81
+
82
+ .reportTitle {
83
+ font-weight: bold;
84
+ }
85
+
86
+ .subTitle {
87
+ display: flex;
88
+ justify-content: space-between;
89
+
90
+ .subTitleItems {
91
+ max-width: 30%;
92
+ }
93
+ }
94
+
95
+ .inputsDiv {
96
+ display: flex;
97
+ justify-content: space-around;
98
+ .inputsDivItem {
99
+ display: flex;
100
+ align-items: center;
101
+ padding: 0 4px;
102
+ white-space: nowrap;
103
+ .inputsDivItemLabel {
104
+ padding: 0 4px;
105
+ }
106
+ }
107
+ }
108
+
109
+ .reportTable {
110
+ width: 100%;
111
+ border-collapse: collapse;
112
+ table-layout:fixed;
113
+ word-break:break-all;
114
+ }
115
+ }
116
+ .reportMainNoPadding {
117
+ text-align: center;
118
+ margin: 0 auto;
119
+ font-size: 16px;
120
+ color: #000;
121
+ background-color: #fff;
122
+ border-radius: 8px;
123
+
124
+ .reportTitle {
125
+ font-weight: bold;
126
+ }
127
+
128
+ .subTitle {
129
+ display: flex;
130
+ justify-content: space-between;
131
+
132
+ .subTitleItems {
133
+ max-width: 30%;
134
+ }
135
+ }
136
+
137
+ .inputsDiv {
138
+ display: flex;
139
+ justify-content: space-between;
140
+ .inputsDivItem {
141
+ display: flex;
142
+ align-items: center;
143
+ padding: 0 4px;
144
+ white-space: nowrap;
145
+ .inputsDivItemLabel {
146
+ padding: 0 4px;
147
+ }
148
+ }
149
+ }
150
+
151
+ .reportTable {
152
+ width: 100%;
153
+ border-collapse: collapse;
154
+ table-layout:fixed;
155
+ word-break:break-all;
156
+ }
157
+ }
158
+ .tools{
159
+ position: fixed;
160
+ right: 2%;
161
+ text-align: right;
162
+ width: 60%;
163
+ cursor: pointer;
164
+ .toolsItem{
165
+ width: 15%;
166
+ margin-right: 3%;
167
+ display: inline-block;
168
+ }
169
+ }
170
+ </style>
171
+ </head>
172
+ <body>
173
+ <!-- 将需要打印的元素内容复制到新窗口中 -->
174
+ ${elementToPrint.innerHTML}
175
+ </body>
176
+ </html>
177
+ `)
178
+ // 延迟执行打印,以确保新窗口的内容已加载完成
179
+ printWindow.document.close() // 关闭文档流,确保内容完全加载
180
+ setTimeout(() => {
181
+ printWindow.print() // 调用打印方法
182
+ printWindow.close()
183
+ }, 500) // 延迟500毫秒后执行打印
184
+ }