af-mobile-client-vue3 1.4.68 → 1.4.70

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 (50) hide show
  1. package/__dummy__ +9 -9
  2. package/build/vite/optimize.ts +36 -36
  3. package/package.json +120 -121
  4. package/public/favicon.svg +4 -4
  5. package/scripts/verifyCommit.js +19 -19
  6. package/src/components/common/MateChat/components/MateChatContent.vue +274 -274
  7. package/src/components/common/MateChat/components/MateChatHeader.vue +337 -337
  8. package/src/components/common/MateChat/index.vue +444 -444
  9. package/src/components/common/MateChat/types.ts +247 -247
  10. package/src/components/common/otherCharge/ChargePrintSelectorAndRemarks.vue +137 -137
  11. package/src/components/common/otherCharge/CodePayment.vue +357 -357
  12. package/src/components/common/otherCharge/FileUploader.vue +602 -602
  13. package/src/components/common/otherCharge/GridFileUploader.vue +846 -846
  14. package/src/components/common/otherCharge/PaymentMethodSelector.vue +202 -202
  15. package/src/components/common/otherCharge/PaymentMethodSelectorCard.vue +45 -45
  16. package/src/components/common/otherCharge/ReceiptModal.vue +273 -273
  17. package/src/components/common/otherCharge/index.ts +43 -43
  18. package/src/components/core/ImageUploader/index.vue +9 -2
  19. package/src/components/data/OtherCharge/OtherChargeItemModal.vue +547 -547
  20. package/src/components/data/UserDetail/types.ts +1 -1
  21. package/src/components/data/XCellList/index.vue +1 -1
  22. package/src/components/data/XReportGrid/XAddReport/index.ts +1 -1
  23. package/src/components/data/XReportGrid/XReportDrawer/index.ts +1 -1
  24. package/src/components/data/XTag/index.vue +10 -10
  25. package/src/components/layout/TabBarLayout/index.vue +40 -40
  26. package/src/hooks/useCommon.ts +9 -9
  27. package/src/plugins/AppData.ts +38 -38
  28. package/src/router/invoiceRoutes.ts +33 -33
  29. package/src/services/api/common.ts +109 -109
  30. package/src/services/api/manage.ts +8 -8
  31. package/src/services/api/search.ts +16 -16
  32. package/src/services/restTools.ts +56 -56
  33. package/src/utils/authority-utils.ts +84 -84
  34. package/src/utils/crypto.ts +39 -39
  35. package/src/utils/queryFormDefaultRangePicker.ts +57 -57
  36. package/src/utils/runEvalFunction.ts +13 -13
  37. package/src/views/component/EvaluateRecordView/index.vue +40 -40
  38. package/src/views/component/MateChat/MateChatView.vue +10 -10
  39. package/src/views/component/XCellDetailView/index.vue +217 -217
  40. package/src/views/component/XCellListView/index.vue +138 -107
  41. package/src/views/component/XFormGroupView/index.vue +82 -78
  42. package/src/views/component/XFormView/index.vue +46 -41
  43. package/src/views/component/XReportFormIframeView/index.vue +47 -47
  44. package/src/views/component/XReportFormView/index.vue +13 -13
  45. package/src/views/component/XSignatureView/index.vue +50 -50
  46. package/src/views/component/notice.vue +46 -46
  47. package/src/views/component/topNav.vue +36 -36
  48. package/src/views/invoiceShow/index.vue +61 -61
  49. package/src/views/user/login/index.vue +22 -22
  50. package/pnpm-lock.yaml +0 -11070
@@ -1,274 +1,274 @@
1
- <script setup lang="ts">
2
- import type { MateChatConfig } from '@af-mobile-client-vue3/components/common/MateChat/types'
3
- import liuliLogo from '@af-mobile-client-vue3/assets/img/component/liuli.png'
4
- import userAvatarImg from '@af-mobile-client-vue3/components/common/MateChat/assets/035-avatar-13.svg'
5
- import MateChatHeader from '@af-mobile-client-vue3/components/common/MateChat/components/MateChatHeader.vue'
6
- import { PromptList } from '@af-mobile-client-vue3/components/common/MateChat/components/PromptList'
7
- import { useMateChat } from '@af-mobile-client-vue3/components/common/MateChat/composables/useMateChat'
8
- import { useDebounceFn } from '@vueuse/core'
9
- import { computed, nextTick, ref, watch } from 'vue'
10
- import 'vant/es/image-preview/style'
11
-
12
- interface MateChatContentProps {
13
- /**
14
- * 完整的配置对象
15
- */
16
- config: MateChatConfig
17
- }
18
-
19
- const props = defineProps<MateChatContentProps>()
20
-
21
- // 从配置中获取的值
22
- const description = computed(() => props.config.description || [])
23
- const introPrompt = computed(() => props.config.introPrompt || [])
24
- const simplePrompt = computed(() => props.config.simplePrompt || [])
25
- const serviceName = computed(() => props.config.serviceName || '智能客服')
26
- const useStream = computed(() => props.config.useStream || false)
27
-
28
- // 初始化 useMateChat
29
- const mateChatInstance = useMateChat(props.config)
30
-
31
- const startPage = computed(() => mateChatInstance.startPage.value)
32
- const inputValue = computed({
33
- get: () => mateChatInstance.inputValue.value,
34
- set: (val: string) => {
35
- mateChatInstance.inputValue.value = val
36
- },
37
- })
38
- const messages = computed(() => mateChatInstance.messages.value)
39
- const newConversation = () => mateChatInstance.newConversation()
40
- const onSubmit = (evt: string) => mateChatInstance.onSubmit(evt)
41
-
42
- // 消息容器的 ref
43
- const messageContainerRef = ref<HTMLElement | null>(null)
44
- // 滚动锚点的 ref
45
- const scrollAnchorRef = ref<HTMLElement | null>(null)
46
-
47
- /**
48
- * 滚动到底部
49
- */
50
- function scrollToBottom() {
51
- nextTick(() => {
52
- // 优先使用滚动锚点元素滚动到底部(最可靠)
53
- if (scrollAnchorRef.value) {
54
- scrollAnchorRef.value.scrollIntoView({ behavior: 'smooth', block: 'end' })
55
- return
56
- }
57
-
58
- // 使用 ref 获取容器并滚动
59
- const container = messageContainerRef.value
60
- if (container instanceof HTMLElement) {
61
- container.scrollTo({
62
- top: container.scrollHeight,
63
- behavior: 'smooth',
64
- })
65
- }
66
- })
67
- }
68
-
69
- // 使用防抖处理滚动函数,延迟 100ms
70
- const debouncedScrollToBottom = useDebounceFn(scrollToBottom, 100)
71
-
72
- // 计算最后一条消息的长度
73
- const lastMessageLength = computed(() => {
74
- const msgList = messages.value
75
- if (msgList.length === 0) {
76
- return 0
77
- }
78
- const lastMsg = msgList[msgList.length - 1]
79
- return lastMsg?.content?.length || 0
80
- })
81
-
82
- // 监听消息数量和最后一条消息的长度变化,自动滚动到底部
83
- // 使用 immediate: false 避免初始化时滚动
84
- watch(
85
- [() => messages.value.length, lastMessageLength],
86
- () => {
87
- debouncedScrollToBottom()
88
- },
89
- { flush: 'post' },
90
- )
91
-
92
- /**
93
- * 处理历史会话选择
94
- */
95
- function handleSelectSession(session: { chatId: string, title: string, lastTime: string }) {
96
- mateChatInstance.loadHistoryMessages(session.chatId)
97
- // 加载历史消息后也需要滚动到底部
98
- // 使用防抖版本,避免频繁滚动
99
- debouncedScrollToBottom()
100
- }
101
- </script>
102
-
103
- <template>
104
- <McLayout class="chat-card">
105
- <MateChatHeader
106
- :show-title="!startPage"
107
- :logo-image="liuliLogo"
108
- :title="serviceName"
109
- :app-id="props.config.appId"
110
- :app-key="props.config.appKey"
111
- @select-session="handleSelectSession"
112
- @new-conversation="newConversation"
113
- />
114
- <McLayoutContent
115
- v-if="startPage"
116
- style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px"
117
- >
118
- <McIntroduction
119
- v-if="description && description.length"
120
- :logo-img="liuliLogo"
121
- :title="serviceName"
122
- :sub-title="`Hi,我是${serviceName}`"
123
- :description="description"
124
- class="McIntroduction"
125
- />
126
- <PromptList
127
- v-if="introPrompt && introPrompt.length"
128
- :list="introPrompt"
129
- @item-click="onSubmit($event.label)"
130
- />
131
- </McLayoutContent>
132
- <McLayoutContent v-else ref="messageContainerRef" class="content-container">
133
- <template v-for="(msg, idx) in messages" :key="idx">
134
- <McBubble
135
- v-if="msg.from === 'user'"
136
- :content="msg.content"
137
- align="right"
138
- :avatar-config="{ imgSrc: userAvatarImg }"
139
- />
140
- <McBubble
141
- v-else-if="msg.from === 'service'"
142
- :content="msg.content"
143
- :avatar-config="{ imgSrc: userAvatarImg }"
144
- />
145
- <McBubble v-else :content="msg.content" :avatar-config="{ imgSrc: liuliLogo }" :loading="msg.loading">
146
- <McMarkdownCard
147
- :content="msg.content"
148
- :typing="msg.typing === true"
149
- />
150
- </McBubble>
151
- </template>
152
- <!-- 滚动锚点 -->
153
- <div ref="scrollAnchorRef" class="scroll-anchor" />
154
- </McLayoutContent>
155
- <div class="shortcut" style="display: flex; align-items: center; gap: 8px">
156
- <PromptList
157
- v-if="!startPage && simplePrompt && simplePrompt.length"
158
- :list="simplePrompt"
159
- direction="horizontal"
160
- variant="shortcut"
161
- class="shortcut-prompt"
162
- style="flex: 1"
163
- @item-click="onSubmit($event.desc)"
164
- />
165
- </div>
166
- <McLayoutSender>
167
- <McInput
168
- :value="inputValue"
169
- placeholder="请输入您的问题,我会为您解答"
170
- :max-length="2000"
171
- :autosize="true"
172
- @change="(e) => (inputValue = e)"
173
- @submit="onSubmit"
174
- />
175
- </McLayoutSender>
176
- </McLayout>
177
- </template>
178
-
179
- <style scoped lang="less">
180
- .chat-card {
181
- width: 100%;
182
- max-width: 1200px;
183
- height: 100%;
184
- background: #ffffff;
185
- border-radius: 24px;
186
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
187
- overflow: hidden;
188
- display: flex;
189
- flex-direction: column;
190
- transition: all 0.3s ease;
191
- padding: 20px;
192
- gap: 8px;
193
- }
194
-
195
- .chat-card:hover {
196
- box-shadow: 0 25px 70px rgba(0, 0, 0, 0.2);
197
- }
198
-
199
- /* 移动端适配 */
200
- @media (max-width: 768px) {
201
- .chat-card {
202
- border-radius: 16px;
203
- padding: 8px;
204
- }
205
- }
206
-
207
- .content-container {
208
- display: flex;
209
- flex-direction: column;
210
- gap: 8px;
211
- overflow: auto;
212
- }
213
-
214
- .scroll-anchor {
215
- height: 1px;
216
- width: 100%;
217
- flex-shrink: 0;
218
- }
219
-
220
- .input-foot-wrapper {
221
- display: flex;
222
- justify-content: space-between;
223
- align-items: center;
224
- width: 100%;
225
- height: 100%;
226
- margin-right: 8px;
227
-
228
- .input-foot-left {
229
- display: flex;
230
- align-items: center;
231
- gap: 8px;
232
-
233
- span {
234
- font-size: 14px;
235
- line-height: 18px;
236
- color: #252b3a;
237
- cursor: pointer;
238
- }
239
-
240
- .input-foot-dividing-line {
241
- width: 1px;
242
- height: 14px;
243
- background-color: #d7d8da;
244
- }
245
-
246
- .input-foot-maxlength {
247
- font-size: 14px;
248
- color: #71757f;
249
- }
250
- }
251
-
252
- .input-foot-right {
253
- .demo-button-content {
254
- font-size: 14px;
255
- }
256
-
257
- & > *:not(:first-child) {
258
- margin-left: 8px;
259
- }
260
- }
261
- }
262
-
263
- :deep(.mc-header-logo-container img) {
264
- width: 32px;
265
- height: 32px;
266
- }
267
-
268
- .McIntroduction {
269
- :deep(.mc-introduction-logo-container img) {
270
- width: 64px;
271
- height: 64px;
272
- }
273
- }
274
- </style>
1
+ <script setup lang="ts">
2
+ import type { MateChatConfig } from '@af-mobile-client-vue3/components/common/MateChat/types'
3
+ import liuliLogo from '@af-mobile-client-vue3/assets/img/component/liuli.png'
4
+ import userAvatarImg from '@af-mobile-client-vue3/components/common/MateChat/assets/035-avatar-13.svg'
5
+ import MateChatHeader from '@af-mobile-client-vue3/components/common/MateChat/components/MateChatHeader.vue'
6
+ import { PromptList } from '@af-mobile-client-vue3/components/common/MateChat/components/PromptList'
7
+ import { useMateChat } from '@af-mobile-client-vue3/components/common/MateChat/composables/useMateChat'
8
+ import { useDebounceFn } from '@vueuse/core'
9
+ import { computed, nextTick, ref, watch } from 'vue'
10
+ import 'vant/es/image-preview/style'
11
+
12
+ interface MateChatContentProps {
13
+ /**
14
+ * 完整的配置对象
15
+ */
16
+ config: MateChatConfig
17
+ }
18
+
19
+ const props = defineProps<MateChatContentProps>()
20
+
21
+ // 从配置中获取的值
22
+ const description = computed(() => props.config.description || [])
23
+ const introPrompt = computed(() => props.config.introPrompt || [])
24
+ const simplePrompt = computed(() => props.config.simplePrompt || [])
25
+ const serviceName = computed(() => props.config.serviceName || '智能客服')
26
+ const useStream = computed(() => props.config.useStream || false)
27
+
28
+ // 初始化 useMateChat
29
+ const mateChatInstance = useMateChat(props.config)
30
+
31
+ const startPage = computed(() => mateChatInstance.startPage.value)
32
+ const inputValue = computed({
33
+ get: () => mateChatInstance.inputValue.value,
34
+ set: (val: string) => {
35
+ mateChatInstance.inputValue.value = val
36
+ },
37
+ })
38
+ const messages = computed(() => mateChatInstance.messages.value)
39
+ const newConversation = () => mateChatInstance.newConversation()
40
+ const onSubmit = (evt: string) => mateChatInstance.onSubmit(evt)
41
+
42
+ // 消息容器的 ref
43
+ const messageContainerRef = ref<HTMLElement | null>(null)
44
+ // 滚动锚点的 ref
45
+ const scrollAnchorRef = ref<HTMLElement | null>(null)
46
+
47
+ /**
48
+ * 滚动到底部
49
+ */
50
+ function scrollToBottom() {
51
+ nextTick(() => {
52
+ // 优先使用滚动锚点元素滚动到底部(最可靠)
53
+ if (scrollAnchorRef.value) {
54
+ scrollAnchorRef.value.scrollIntoView({ behavior: 'smooth', block: 'end' })
55
+ return
56
+ }
57
+
58
+ // 使用 ref 获取容器并滚动
59
+ const container = messageContainerRef.value
60
+ if (container instanceof HTMLElement) {
61
+ container.scrollTo({
62
+ top: container.scrollHeight,
63
+ behavior: 'smooth',
64
+ })
65
+ }
66
+ })
67
+ }
68
+
69
+ // 使用防抖处理滚动函数,延迟 100ms
70
+ const debouncedScrollToBottom = useDebounceFn(scrollToBottom, 100)
71
+
72
+ // 计算最后一条消息的长度
73
+ const lastMessageLength = computed(() => {
74
+ const msgList = messages.value
75
+ if (msgList.length === 0) {
76
+ return 0
77
+ }
78
+ const lastMsg = msgList[msgList.length - 1]
79
+ return lastMsg?.content?.length || 0
80
+ })
81
+
82
+ // 监听消息数量和最后一条消息的长度变化,自动滚动到底部
83
+ // 使用 immediate: false 避免初始化时滚动
84
+ watch(
85
+ [() => messages.value.length, lastMessageLength],
86
+ () => {
87
+ debouncedScrollToBottom()
88
+ },
89
+ { flush: 'post' },
90
+ )
91
+
92
+ /**
93
+ * 处理历史会话选择
94
+ */
95
+ function handleSelectSession(session: { chatId: string, title: string, lastTime: string }) {
96
+ mateChatInstance.loadHistoryMessages(session.chatId)
97
+ // 加载历史消息后也需要滚动到底部
98
+ // 使用防抖版本,避免频繁滚动
99
+ debouncedScrollToBottom()
100
+ }
101
+ </script>
102
+
103
+ <template>
104
+ <McLayout class="chat-card">
105
+ <MateChatHeader
106
+ :show-title="!startPage"
107
+ :logo-image="liuliLogo"
108
+ :title="serviceName"
109
+ :app-id="props.config.appId"
110
+ :app-key="props.config.appKey"
111
+ @select-session="handleSelectSession"
112
+ @new-conversation="newConversation"
113
+ />
114
+ <McLayoutContent
115
+ v-if="startPage"
116
+ style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px"
117
+ >
118
+ <McIntroduction
119
+ v-if="description && description.length"
120
+ :logo-img="liuliLogo"
121
+ :title="serviceName"
122
+ :sub-title="`Hi,我是${serviceName}`"
123
+ :description="description"
124
+ class="McIntroduction"
125
+ />
126
+ <PromptList
127
+ v-if="introPrompt && introPrompt.length"
128
+ :list="introPrompt"
129
+ @item-click="onSubmit($event.label)"
130
+ />
131
+ </McLayoutContent>
132
+ <McLayoutContent v-else ref="messageContainerRef" class="content-container">
133
+ <template v-for="(msg, idx) in messages" :key="idx">
134
+ <McBubble
135
+ v-if="msg.from === 'user'"
136
+ :content="msg.content"
137
+ align="right"
138
+ :avatar-config="{ imgSrc: userAvatarImg }"
139
+ />
140
+ <McBubble
141
+ v-else-if="msg.from === 'service'"
142
+ :content="msg.content"
143
+ :avatar-config="{ imgSrc: userAvatarImg }"
144
+ />
145
+ <McBubble v-else :content="msg.content" :avatar-config="{ imgSrc: liuliLogo }" :loading="msg.loading">
146
+ <McMarkdownCard
147
+ :content="msg.content"
148
+ :typing="msg.typing === true"
149
+ />
150
+ </McBubble>
151
+ </template>
152
+ <!-- 滚动锚点 -->
153
+ <div ref="scrollAnchorRef" class="scroll-anchor" />
154
+ </McLayoutContent>
155
+ <div class="shortcut" style="display: flex; align-items: center; gap: 8px">
156
+ <PromptList
157
+ v-if="!startPage && simplePrompt && simplePrompt.length"
158
+ :list="simplePrompt"
159
+ direction="horizontal"
160
+ variant="shortcut"
161
+ class="shortcut-prompt"
162
+ style="flex: 1"
163
+ @item-click="onSubmit($event.desc)"
164
+ />
165
+ </div>
166
+ <McLayoutSender>
167
+ <McInput
168
+ :value="inputValue"
169
+ placeholder="请输入您的问题,我会为您解答"
170
+ :max-length="2000"
171
+ :autosize="true"
172
+ @change="(e) => (inputValue = e)"
173
+ @submit="onSubmit"
174
+ />
175
+ </McLayoutSender>
176
+ </McLayout>
177
+ </template>
178
+
179
+ <style scoped lang="less">
180
+ .chat-card {
181
+ width: 100%;
182
+ max-width: 1200px;
183
+ height: 100%;
184
+ background: #ffffff;
185
+ border-radius: 24px;
186
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
187
+ overflow: hidden;
188
+ display: flex;
189
+ flex-direction: column;
190
+ transition: all 0.3s ease;
191
+ padding: 20px;
192
+ gap: 8px;
193
+ }
194
+
195
+ .chat-card:hover {
196
+ box-shadow: 0 25px 70px rgba(0, 0, 0, 0.2);
197
+ }
198
+
199
+ /* 移动端适配 */
200
+ @media (max-width: 768px) {
201
+ .chat-card {
202
+ border-radius: 16px;
203
+ padding: 8px;
204
+ }
205
+ }
206
+
207
+ .content-container {
208
+ display: flex;
209
+ flex-direction: column;
210
+ gap: 8px;
211
+ overflow: auto;
212
+ }
213
+
214
+ .scroll-anchor {
215
+ height: 1px;
216
+ width: 100%;
217
+ flex-shrink: 0;
218
+ }
219
+
220
+ .input-foot-wrapper {
221
+ display: flex;
222
+ justify-content: space-between;
223
+ align-items: center;
224
+ width: 100%;
225
+ height: 100%;
226
+ margin-right: 8px;
227
+
228
+ .input-foot-left {
229
+ display: flex;
230
+ align-items: center;
231
+ gap: 8px;
232
+
233
+ span {
234
+ font-size: 14px;
235
+ line-height: 18px;
236
+ color: #252b3a;
237
+ cursor: pointer;
238
+ }
239
+
240
+ .input-foot-dividing-line {
241
+ width: 1px;
242
+ height: 14px;
243
+ background-color: #d7d8da;
244
+ }
245
+
246
+ .input-foot-maxlength {
247
+ font-size: 14px;
248
+ color: #71757f;
249
+ }
250
+ }
251
+
252
+ .input-foot-right {
253
+ .demo-button-content {
254
+ font-size: 14px;
255
+ }
256
+
257
+ & > *:not(:first-child) {
258
+ margin-left: 8px;
259
+ }
260
+ }
261
+ }
262
+
263
+ :deep(.mc-header-logo-container img) {
264
+ width: 32px;
265
+ height: 32px;
266
+ }
267
+
268
+ .McIntroduction {
269
+ :deep(.mc-introduction-logo-container img) {
270
+ width: 64px;
271
+ height: 64px;
272
+ }
273
+ }
274
+ </style>