af-mobile-client-vue3 1.5.84 → 1.5.86

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.
package/.env.development CHANGED
@@ -1,2 +1 @@
1
1
  NODE_ENV=development
2
- VITE_RSA_PRIVATE_KEY=MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIRrmftLDHCQqREEJ132Onu+W3vmFbdF7QD751SrcDDGDTfzuz1zBuElvkHhuDBb7KZkXrCIe+MhvX2IvxcLObl3faX+evYlnfj2HRbF0hIpQLuIq22tL06ZcV5w7wqLxUZRpFElIFm8gZTkUvfKXVuHw89e4daDVhU5hK3GHNGTAgMBAAECgYABiINrFaE1E8pkBYx1JJA5yuhL73aUktfd2TeCU00vFg6kyrWCI85Sa2RKu/6CJNZWeOFgdubEUv7a22tRrNIZb3yUMaqtTwSso78mspIOJqjWXTkTH9WPElfTcdpdIse/lgZtPz6egxkuhadSvwrM9Y6NgusiW/5+x95Ct08iOQJBAN5aK+7uISURvGQj2EaRtgGEd8+d4oHl+BYvvTeG3qSgUikHQW3j0sp4gXPw2kxw6sjVgLFOc4FB6LGqwzOTzokCQQCYdYG8ty3Uo/ebUlNzeJFxHXjy/KvBSytAUzAXkRu3nZrkEaPQsi3dgOkZgk+F1fMDzfQ4EbDIU6xvqOoZXHg7AkATCW9XfoXR8anKfRMoP5Nwn9HOMbtR2cmaxK2TknV/bMZ8AsYETYwfj5+tuIJIJybC2RyykX/sIiN1CqS5xr7ZAkArj19rMRdaKyMi8MnBM1Cy9g3Jt2HHj5ejAGG8SgyWUOShh1y70z0BjcSMMkxQXAncK2s83ekZw7aADM4eQupjAkARRgTwwMOnn3IoKmQusKhZk0uxilZ4Zc2LH6Z4GiWnvteM0W8Zw4Z1lJUcjgQq3dGqL2RdmzeQZ+HgPIOXrZVK
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "af-mobile-client-vue3",
3
3
  "type": "module",
4
- "version": "1.5.84",
4
+ "version": "1.5.86",
5
5
  "packageManager": "pnpm@10.13.1",
6
6
  "description": "Vue + Vite component lib",
7
7
  "engines": {
@@ -1,326 +1,325 @@
1
- <script setup lang="ts">
2
- import { post } from '@af-mobile-client-vue3/services/restTools'
3
- import useUserStore from '@af-mobile-client-vue3/stores/modules/user'
4
- import { mobileUtil } from '@af-mobile-client-vue3/utils/mobileUtil'
5
- import { Badge as VanBadge, Icon as VanIcon } from 'vant'
6
- import { onMounted, onUnmounted, ref } from 'vue'
7
- import { closeWebSocket, initWebSocket } from './webSocket'
8
- import 'vant/es/badge/style'
9
- import 'vant/es/icon/style'
10
-
11
- interface Props {
12
- iconColor?: string
13
- }
14
-
15
- const props = withDefaults(defineProps<Props>(), {
16
- iconColor: '#666',
17
- })
18
-
19
- const userInfo = useUserStore().getUserInfo()
20
-
21
- // 未读消息数量
22
- const unreadCount = ref(0)
23
-
24
- // 打开消息下拉菜单
25
- const isShowMessageDropdown = ref(false)
26
-
27
- // 消息列表数据
28
- const messages = ref<any[]>([])
29
-
30
- // 组件根元素的引用
31
- const messageNotificationRef = ref<HTMLElement | null>(null)
32
-
33
- // 获取消息数据
34
- async function fetchMessages() {
35
- const param = {
36
- userId: `${userInfo.id}:phone`, // |phone
37
- typeList: '\'phone\'', // phone
38
- pageNo: 1,
39
- pageSize: 100,
40
- }
41
- const res = await post('/af-system/logic/getNotificationListByType', param)
42
- messages.value = (res || []).map((item: any) => {
43
- const event: any = JSON.parse(item.f_event || '{}')
44
- return {
45
- id: item.id,
46
- type: event.type,
47
- time: item.f_input_date,
48
- title: event.title || '',
49
- status: item.f_state,
50
- content: event.description || '',
51
- }
52
- })
53
- }
54
-
55
- // 获取未读消息数量
56
- async function fetchMessagesCount() {
57
- const param = {
58
- userId: `${userInfo.id}:phone`, // |phone
59
- typeList: '\'phone\'', // phone
60
- }
61
- const count = await post('/af-system/logic/getNotificationCount', param)
62
- unreadCount.value = count.count
63
- }
64
-
65
- // 处理 WebSocket 消息
66
- function createMessageCallback(message: any) {
67
- fetchMessagesCount()
68
- fetchMessages()
69
- }
70
- // 处理 不同的业务
71
- function sendMessageCallback(message: any) {
72
- console.log('>>>> 处理业务', JSON.stringify(message))
73
- if (message.businessType === 'audio') {
74
- // 播放响铃, 响铃文件为 message.audioName
75
- mobileUtil.execute({
76
- funcName: 'playAudio',
77
- param: {
78
- fileName: message.audioName,
79
- },
80
- callbackFunc: (result: any) => {
81
- // {"status":"success","data":{"message":"音频播放成功","fileName":"anjian.mp3","path":"assets/audio/anjian.mp3"}}
82
- },
83
- })
84
- }
85
- }
86
-
87
- // 全部标记为已读(清空消息列表)
88
- function markAllAsRead() {
89
- if (messages.value.length === 0)
90
- return
91
-
92
- const messageIds = messages.value.map(msg => msg.id).join(',')
93
- markAsRead(messageIds)
94
- }
95
-
96
- // 单条消息标记为已读
97
- function markAsRead(id: string | number) {
98
- post('/af-system/logic/confirmMessage', {
99
- id,
100
- f_state: 2,
101
- }).then(() => {
102
- fetchMessages()
103
- fetchMessagesCount()
104
- })
105
- }
106
-
107
- function handleIconClick(message: any) {
108
- // 乐观更新为已读状态,使图标立刻变绿
109
- message.status = 2
110
- setTimeout(() => {
111
- markAsRead(message.id)
112
- }, 200)
113
- }
114
-
115
- function showMessageDropdown() {
116
- isShowMessageDropdown.value = !isShowMessageDropdown.value
117
- if (isShowMessageDropdown.value) {
118
- fetchMessages()
119
- }
120
- }
121
-
122
- // 处理全局点击事件
123
- function handleDocumentClick(event: MouseEvent) {
124
- if (messageNotificationRef.value && !messageNotificationRef.value.contains(event.target as Node)) {
125
- isShowMessageDropdown.value = false
126
- }
127
- }
128
-
129
- onMounted(() => {
130
- fetchMessages()
131
- fetchMessagesCount()
132
- // 初始化 WebSocket 连接
133
- initWebSocket(userInfo.id, sendMessageCallback, createMessageCallback)
134
- // 添加全局点击事件监听器
135
- document.addEventListener('click', handleDocumentClick)
136
- })
137
-
138
- onUnmounted(() => {
139
- closeWebSocket()
140
- // 移除全局点击事件监听器
141
- document.removeEventListener('click', handleDocumentClick)
142
- })
143
- </script>
144
-
145
- <template>
146
- <div ref="messageNotificationRef" class="message_icon" @click="showMessageDropdown">
147
- <VanBadge v-if="unreadCount > 0" :content="unreadCount" max="99">
148
- <VanIcon name="bell" :color="props.iconColor" />
149
- </VanBadge>
150
- <VanIcon v-else name="bell" :color="props.iconColor" />
151
- </div>
152
-
153
- <div v-if="isShowMessageDropdown" class="message_overlay" @click="isShowMessageDropdown = false" />
154
-
155
- <div v-show="isShowMessageDropdown" class="message_dropdown" @click.stop>
156
- <div class="message_header">
157
- <span class="label">消息通知</span>
158
- <span class="action" @click="markAllAsRead">全部已读</span>
159
- </div>
160
- <div class="message_list">
161
- <template v-if="messages.length > 0">
162
- <div
163
- v-for="message in messages"
164
- :key="message.id"
165
- class="message_item"
166
- :class="{ info: message.type === 'info', warning: message.type === 'warning' }"
167
- >
168
- <!-- 第一行:div1 + div2 -->
169
- <div class="message_row">
170
- <!-- div1:标题+时间 -->
171
- <div class="message_left">
172
- <p class="message_title">
173
- {{ message.title }}
174
- </p>
175
- <p class="message_time">
176
- {{ message.time }}
177
- </p>
178
- </div>
179
- <!-- div2:图标 -->
180
- <div class="message_right">
181
- <VanIcon
182
- name="checked"
183
- :color="message.status === 2 ? '#52c41a' : '#999'"
184
- size="28"
185
- @click.stop="handleIconClick(message)"
186
- />
187
- </div>
188
- </div>
189
- <!-- 第二行:div3 内容 -->
190
- <div class="message_content">
191
- <p class="message_text">
192
- {{ message.content }}
193
- </p>
194
- </div>
195
- </div>
196
- </template>
197
- <div v-else class="empty_message">
198
- 暂无未读消息
199
- </div>
200
- </div>
201
- </div>
202
- </template>
203
-
204
- <style scoped lang="less">
205
- .message_dropdown {
206
- position: absolute;
207
- top: 56px;
208
- left: 0;
209
- right: 0;
210
- background-color: #fff;
211
- box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
212
- z-index: 10001;
213
- max-height: 400px;
214
- overflow-y: auto;
215
-
216
- .message_header {
217
- display: flex;
218
- justify-content: space-between;
219
- align-items: center;
220
- padding: 12px 16px;
221
- border-bottom: 1px solid #eee;
222
-
223
- .label {
224
- font-size: 14px;
225
- color: #999;
226
- }
227
- .action {
228
- font-size: 14px;
229
- color: #1989fa;
230
- cursor: pointer;
231
- }
232
- }
233
-
234
- .message_list {
235
- .message_item {
236
- padding: 12px 16px;
237
- border-bottom: 1px solid #f5f5f5;
238
-
239
- &.info {
240
- background-color: #eff6ff;
241
- }
242
- &.warning {
243
- background-color: #fff7ed;
244
- }
245
-
246
- .message_row {
247
- display: flex;
248
- justify-content: space-between;
249
- align-items: flex-start;
250
- }
251
-
252
- .message_left {
253
- flex: 1;
254
- min-width: 0;
255
-
256
- .message_title {
257
- font-size: 14px;
258
- font-weight: 500;
259
- color: #333;
260
- margin: 0;
261
- white-space: nowrap;
262
- overflow: hidden;
263
- text-overflow: ellipsis;
264
- }
265
-
266
- .message_time {
267
- font-size: 12px;
268
- color: #999;
269
- margin: 4px 0 0 0;
270
- }
271
- }
272
-
273
- .message_right {
274
- flex: 0 0 auto;
275
- display: flex;
276
- align-items: center;
277
- padding-left: 8px;
278
-
279
- .van-icon {
280
- font-size: 18px;
281
- color: #999;
282
- }
283
- }
284
-
285
- .message_content {
286
- margin-top: 8px;
287
-
288
- .message_text {
289
- border-radius: 4px;
290
- font-size: 13px;
291
- color: #666;
292
- background-color: #fafafc;
293
- margin: 0;
294
- padding: 8px 12px;
295
- line-height: 1.4;
296
- }
297
- }
298
- }
299
-
300
- .empty_message {
301
- padding: 60px 0;
302
- text-align: center;
303
- color: #999;
304
- font-size: 14px;
305
- }
306
- }
307
- }
308
-
309
- .message_overlay {
310
- position: fixed;
311
- inset: 0;
312
- background: rgba(0, 0, 0, 0.45);
313
- z-index: 10001;
314
- margin-top: 56px;
315
- margin-bottom: 50px;
316
- }
317
- .message_icon {
318
- padding: 8px;
319
- position: relative;
320
- cursor: pointer;
321
-
322
- .van-icon {
323
- font-size: 20px;
324
- }
325
- }
326
- </style>
1
+ <script setup lang="ts">
2
+ import { post } from '@af-mobile-client-vue3/services/restTools'
3
+ import useUserStore from '@af-mobile-client-vue3/stores/modules/user'
4
+ import { mobileUtil } from '@af-mobile-client-vue3/utils/mobileUtil'
5
+ import { Badge as VanBadge, Icon as VanIcon } from 'vant'
6
+ import { onMounted, onUnmounted, ref } from 'vue'
7
+ import { closeWebSocket, initWebSocket } from './webSocket'
8
+ import 'vant/es/badge/style'
9
+ import 'vant/es/icon/style'
10
+
11
+ interface Props {
12
+ iconColor?: string
13
+ }
14
+
15
+ const props = withDefaults(defineProps<Props>(), {
16
+ iconColor: '#666',
17
+ })
18
+
19
+ const userInfo = useUserStore().getUserInfo()
20
+
21
+ // 未读消息数量
22
+ const unreadCount = ref(0)
23
+
24
+ // 打开消息下拉菜单
25
+ const isShowMessageDropdown = ref(false)
26
+
27
+ // 消息列表数据
28
+ const messages = ref<any[]>([])
29
+
30
+ // 组件根元素的引用
31
+ const messageNotificationRef = ref<HTMLElement | null>(null)
32
+
33
+ // 获取消息数据
34
+ async function fetchMessages() {
35
+ const param = {
36
+ userId: `${userInfo.id}:phone`, // |phone
37
+ typeList: '\'phone\'', // phone
38
+ pageNo: 1,
39
+ pageSize: 100,
40
+ }
41
+ const res = await post('/af-system/logic/getNotificationListByType', param)
42
+ messages.value = (res || []).map((item: any) => {
43
+ const event: any = JSON.parse(item.f_event || '{}')
44
+ return {
45
+ id: item.id,
46
+ type: event.type,
47
+ time: item.f_input_date,
48
+ title: event.title || '',
49
+ status: item.f_state,
50
+ content: event.description || '',
51
+ }
52
+ })
53
+ }
54
+
55
+ // 获取未读消息数量
56
+ async function fetchMessagesCount() {
57
+ const param = {
58
+ userId: `${userInfo.id}:phone`, // |phone
59
+ typeList: '\'phone\'', // phone
60
+ }
61
+ const count = await post('/af-system/logic/getNotificationCount', param)
62
+ unreadCount.value = count.count
63
+ }
64
+
65
+ // 处理 WebSocket 消息
66
+ function createMessageCallback(message: any) {
67
+ fetchMessagesCount()
68
+ fetchMessages()
69
+ }
70
+ // 处理 不同的业务
71
+ function sendMessageCallback(message: any) {
72
+ console.log('>>>> 处理业务', JSON.stringify(message))
73
+ if (message.businessType === 'audio') {
74
+ // 播放响铃, 响铃文件为 message.audioName
75
+ mobileUtil.execute({
76
+ funcName: 'playAudio',
77
+ param: {
78
+ fileName: message.audioName,
79
+ },
80
+ callbackFunc: (result: any) => {
81
+ // {"status":"success","data":{"message":"音频播放成功","fileName":"anjian.mp3","path":"assets/audio/anjian.mp3"}}
82
+ },
83
+ })
84
+ }
85
+ }
86
+
87
+ // 全部标记为已读(清空消息列表)
88
+ function markAllAsRead() {
89
+ if (messages.value.length === 0)
90
+ return
91
+
92
+ const messageIds = messages.value.map(msg => msg.id).join(',')
93
+ markAsRead(messageIds)
94
+ }
95
+
96
+ // 单条消息标记为已读
97
+ function markAsRead(id: string | number) {
98
+ post('/af-system/logic/confirmMessage', {
99
+ id,
100
+ f_state: 2,
101
+ }).then(() => {
102
+ fetchMessages()
103
+ fetchMessagesCount()
104
+ })
105
+ }
106
+
107
+ function handleIconClick(message: any) {
108
+ // 乐观更新为已读状态,使图标立刻变绿
109
+ message.status = 2
110
+ setTimeout(() => {
111
+ markAsRead(message.id)
112
+ }, 200)
113
+ }
114
+
115
+ function showMessageDropdown() {
116
+ isShowMessageDropdown.value = !isShowMessageDropdown.value
117
+ if (isShowMessageDropdown.value) {
118
+ fetchMessages()
119
+ }
120
+ }
121
+
122
+ // 处理全局点击事件
123
+ function handleDocumentClick(event: MouseEvent) {
124
+ if (messageNotificationRef.value && !messageNotificationRef.value.contains(event.target as Node)) {
125
+ isShowMessageDropdown.value = false
126
+ }
127
+ }
128
+
129
+ onMounted(() => {
130
+ fetchMessagesCount()
131
+ // 初始化 WebSocket 连接
132
+ initWebSocket(userInfo.id, sendMessageCallback, createMessageCallback)
133
+ // 添加全局点击事件监听器
134
+ document.addEventListener('click', handleDocumentClick)
135
+ })
136
+
137
+ onUnmounted(() => {
138
+ closeWebSocket()
139
+ // 移除全局点击事件监听器
140
+ document.removeEventListener('click', handleDocumentClick)
141
+ })
142
+ </script>
143
+
144
+ <template>
145
+ <div ref="messageNotificationRef" class="message_icon" @click="showMessageDropdown">
146
+ <VanBadge v-if="unreadCount > 0" :content="unreadCount" max="99">
147
+ <VanIcon name="bell" :color="props.iconColor" />
148
+ </VanBadge>
149
+ <VanIcon v-else name="bell" :color="props.iconColor" />
150
+ </div>
151
+
152
+ <div v-if="isShowMessageDropdown" class="message_overlay" @click="isShowMessageDropdown = false" />
153
+
154
+ <div v-show="isShowMessageDropdown" class="message_dropdown" @click.stop>
155
+ <div class="message_header">
156
+ <span class="label">消息通知</span>
157
+ <span class="action" @click="markAllAsRead">全部已读</span>
158
+ </div>
159
+ <div class="message_list">
160
+ <template v-if="messages.length > 0">
161
+ <div
162
+ v-for="message in messages"
163
+ :key="message.id"
164
+ class="message_item"
165
+ :class="{ info: message.type === 'info', warning: message.type === 'warning' }"
166
+ >
167
+ <!-- 第一行:div1 + div2 -->
168
+ <div class="message_row">
169
+ <!-- div1:标题+时间 -->
170
+ <div class="message_left">
171
+ <p class="message_title">
172
+ {{ message.title }}
173
+ </p>
174
+ <p class="message_time">
175
+ {{ message.time }}
176
+ </p>
177
+ </div>
178
+ <!-- div2:图标 -->
179
+ <div class="message_right">
180
+ <VanIcon
181
+ name="checked"
182
+ :color="message.status === 2 ? '#52c41a' : '#999'"
183
+ size="28"
184
+ @click.stop="handleIconClick(message)"
185
+ />
186
+ </div>
187
+ </div>
188
+ <!-- 第二行:div3 内容 -->
189
+ <div class="message_content">
190
+ <p class="message_text">
191
+ {{ message.content }}
192
+ </p>
193
+ </div>
194
+ </div>
195
+ </template>
196
+ <div v-else class="empty_message">
197
+ 暂无未读消息
198
+ </div>
199
+ </div>
200
+ </div>
201
+ </template>
202
+
203
+ <style scoped lang="less">
204
+ .message_dropdown {
205
+ position: absolute;
206
+ top: 56px;
207
+ left: 0;
208
+ right: 0;
209
+ background-color: #fff;
210
+ box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
211
+ z-index: 10001;
212
+ max-height: 400px;
213
+ overflow-y: auto;
214
+
215
+ .message_header {
216
+ display: flex;
217
+ justify-content: space-between;
218
+ align-items: center;
219
+ padding: 12px 16px;
220
+ border-bottom: 1px solid #eee;
221
+
222
+ .label {
223
+ font-size: 14px;
224
+ color: #999;
225
+ }
226
+ .action {
227
+ font-size: 14px;
228
+ color: #1989fa;
229
+ cursor: pointer;
230
+ }
231
+ }
232
+
233
+ .message_list {
234
+ .message_item {
235
+ padding: 12px 16px;
236
+ border-bottom: 1px solid #f5f5f5;
237
+
238
+ &.info {
239
+ background-color: #eff6ff;
240
+ }
241
+ &.warning {
242
+ background-color: #fff7ed;
243
+ }
244
+
245
+ .message_row {
246
+ display: flex;
247
+ justify-content: space-between;
248
+ align-items: flex-start;
249
+ }
250
+
251
+ .message_left {
252
+ flex: 1;
253
+ min-width: 0;
254
+
255
+ .message_title {
256
+ font-size: 14px;
257
+ font-weight: 500;
258
+ color: #333;
259
+ margin: 0;
260
+ white-space: nowrap;
261
+ overflow: hidden;
262
+ text-overflow: ellipsis;
263
+ }
264
+
265
+ .message_time {
266
+ font-size: 12px;
267
+ color: #999;
268
+ margin: 4px 0 0 0;
269
+ }
270
+ }
271
+
272
+ .message_right {
273
+ flex: 0 0 auto;
274
+ display: flex;
275
+ align-items: center;
276
+ padding-left: 8px;
277
+
278
+ .van-icon {
279
+ font-size: 18px;
280
+ color: #999;
281
+ }
282
+ }
283
+
284
+ .message_content {
285
+ margin-top: 8px;
286
+
287
+ .message_text {
288
+ border-radius: 4px;
289
+ font-size: 13px;
290
+ color: #666;
291
+ background-color: #fafafc;
292
+ margin: 0;
293
+ padding: 8px 12px;
294
+ line-height: 1.4;
295
+ }
296
+ }
297
+ }
298
+
299
+ .empty_message {
300
+ padding: 60px 0;
301
+ text-align: center;
302
+ color: #999;
303
+ font-size: 14px;
304
+ }
305
+ }
306
+ }
307
+
308
+ .message_overlay {
309
+ position: fixed;
310
+ inset: 0;
311
+ background: rgba(0, 0, 0, 0.45);
312
+ z-index: 10001;
313
+ margin-top: 56px;
314
+ margin-bottom: 50px;
315
+ }
316
+ .message_icon {
317
+ padding: 8px;
318
+ position: relative;
319
+ cursor: pointer;
320
+
321
+ .van-icon {
322
+ font-size: 20px;
323
+ }
324
+ }
325
+ </style>
@@ -28,7 +28,8 @@ export function initWebSocket(notify: string | null = null, sendCallback: (messa
28
28
  }
29
29
 
30
30
  // 初始化 WebSocket
31
- websocket = new WebSocket(`ws:${window.location.host}/socket/af-system/sendMessage?userId=${notifyId}:phone`)
31
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
32
+ websocket = new WebSocket(`${protocol}${window.location.host}/socket/af-system/sendMessage?userId=${notifyId}:phone`)
32
33
 
33
34
  // WebSocket 打开连接时触发
34
35
  websocket.onopen = () => {
@@ -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
+ }
@@ -26,8 +26,8 @@ export interface WebConfig {
26
26
  hiddenTraditionalLogin: boolean
27
27
  isFaceRecognition: boolean // 登录是否需要人脸识别
28
28
  intervalFaceRecognition: boolean // 登录是否需要开启定时人脸识别
29
- faceIntervalMinutes: number // 定时时间
30
- faceRetryCount: number // 重试次数
29
+ faceIntervalMinutes: number // 定时时间 单位分钟
30
+ faceRetryCount: number // 定时验证 重试次数
31
31
  getPlatformUser: boolean // 获取外部用户信息
32
32
  navigationStyle: any // app顶部导航区域样式控制
33
33
  }
@@ -247,6 +247,13 @@ export const useUserStore = defineStore('app-user', () => {
247
247
  }
248
248
  // save token
249
249
  setToken(data.access_token)
250
+ const LoginTicket = crypto.AESEncrypt(JSON.stringify(params), '3KMKqvgwR8ULbR8Z')
251
+ if (data.session && useSettingStore().getSetting().requestEncrypt) {
252
+ const k = encryptUtil.RSADecrypt(data.session as string)
253
+ localStorage.setItem('v4-session-key', k)
254
+ secureStorageWrite('v4-session-key', k)
255
+ }
256
+ Storage.set('LoginTicket', LoginTicket)
250
257
  return Promise.resolve(data)
251
258
  }
252
259
  catch (error) {
@@ -1,27 +1,27 @@
1
- // 时间工具:提供简单的日期时间格式化
2
-
3
- export function pad2(num: number): string {
4
- return num < 10 ? `0${num}` : `${num}`
5
- }
6
-
7
- /**
8
- * 按照简单占位符格式化当前时间
9
- * 支持占位:YYYY MM DD HH mm ss
10
- * @param format 默认 'YYYY-MM-DD HH:mm:ss'
11
- */
12
- export function formatNow(format: string = 'YYYY-MM-DD HH:mm:ss'): string {
13
- const d = new Date()
14
- const map: Record<string, string> = {
15
- YYYY: `${d.getFullYear()}`,
16
- MM: pad2(d.getMonth() + 1),
17
- DD: pad2(d.getDate()),
18
- HH: pad2(d.getHours()),
19
- mm: pad2(d.getMinutes()),
20
- ss: pad2(d.getSeconds()),
21
- }
22
- let out = format
23
- Object.keys(map).forEach((k) => {
24
- out = out.replace(new RegExp(k, 'g'), map[k])
25
- })
26
- return out
27
- }
1
+ // 时间工具:提供简单的日期时间格式化
2
+
3
+ export function pad2(num: number): string {
4
+ return num < 10 ? `0${num}` : `${num}`
5
+ }
6
+
7
+ /**
8
+ * 按照简单占位符格式化当前时间
9
+ * 支持占位:YYYY MM DD HH mm ss
10
+ * @param format 默认 'YYYY-MM-DD HH:mm:ss'
11
+ */
12
+ export function formatNow(format: string = 'YYYY-MM-DD HH:mm:ss'): string {
13
+ const d = new Date()
14
+ const map: Record<string, string> = {
15
+ YYYY: `${d.getFullYear()}`,
16
+ MM: pad2(d.getMonth() + 1),
17
+ DD: pad2(d.getDate()),
18
+ HH: pad2(d.getHours()),
19
+ mm: pad2(d.getMinutes()),
20
+ ss: pad2(d.getSeconds()),
21
+ }
22
+ let out = format
23
+ Object.keys(map).forEach((k) => {
24
+ out = out.replace(new RegExp(k, 'g'), map[k])
25
+ })
26
+ return out
27
+ }
@@ -5,7 +5,7 @@ import useSettingStore from '@af-mobile-client-vue3/stores/modules/setting'
5
5
  import useUserStore from '@af-mobile-client-vue3/stores/modules/user'
6
6
  import { openDrivingConfigPopup } from '@af-mobile-client-vue3/utils/driving/drivingUtils'
7
7
  import { mobileUtil } from '@af-mobile-client-vue3/utils/mobileUtil'
8
- import { Dialog as vanDialog, Icon as vanIcon, Sticky as VanSticky, Switch as VanSwitch,
8
+ import { Dialog as vanDialog, Icon as vanIcon, Switch as VanSwitch,
9
9
  } from 'vant'
10
10
  import { onMounted, onUnmounted, ref } from 'vue'
11
11
  import { useRouter } from 'vue-router'