@uxda/appkit 1.2.63 → 1.2.65

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxda/appkit",
3
- "version": "1.2.63",
3
+ "version": "1.2.65",
4
4
  "description": "小程序应用开发包",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.ts",
@@ -113,13 +113,13 @@ const isFoucs = ref(props.focus)
113
113
  left: 40px;
114
114
  background: transparent;
115
115
  .dd-search__form {
116
- background: $bg-default;
116
+ background: #f1f3f5;
117
117
  border-color: transparent;
118
118
  }
119
119
  }
120
120
  &.focus {
121
121
  .dd-search__form {
122
- border-color: $primary-color;
122
+ border-color: #017fff;
123
123
  }
124
124
  }
125
125
  &__placeholder {
@@ -129,7 +129,6 @@ const isFoucs = ref(props.focus)
129
129
  flex: 1;
130
130
  box-sizing: border-box;
131
131
  height: 36px;
132
- //border: 1px solid rgba(180, 180, 180, 0.2);
133
132
  border-radius: 5px;
134
133
  display: flex;
135
134
  align-items: center;
@@ -144,7 +143,7 @@ const isFoucs = ref(props.focus)
144
143
  width: 100%;
145
144
  box-sizing: border-box;
146
145
  padding: 0 10px;
147
- caret-color: var(--second-color);
146
+ caret-color: #017fff;
148
147
  }
149
148
  &__prefix,
150
149
  &__suffix {
@@ -155,15 +154,12 @@ const isFoucs = ref(props.focus)
155
154
  height: 33px;
156
155
  line-height: 33px;
157
156
  padding: 0 10px;
158
- font-size: var(--primary-size);
159
- color: var(--second-color);
157
+ font-size: 16px;
158
+ color: #017fff;
160
159
  }
161
160
  &.disabled &__suffix {
162
161
  display: none;
163
162
  }
164
- //&.disabled &__btn {
165
- // display: none;
166
- //}
167
163
  &.disabled &__control {
168
164
  flex: 1;
169
165
  width: fit-content;
@@ -19,7 +19,7 @@
19
19
  src="https://cdn.ddjf.com/static/images/customer-center/notice-icon.png"
20
20
  alt=""
21
21
  />
22
- <div class="notice-banner-text" style="white-space: pre-wrap">
22
+ <div class="notice-banner-text">
23
23
  {{ item.context }}
24
24
  </div>
25
25
  <div class="notice-banner-btn" @click="onDetail(item)">详情</div>
@@ -150,7 +150,7 @@ const onClose = debounce((item: any, index: number) => {
150
150
  })
151
151
  bannerMessages.value.splice(index, 1)
152
152
 
153
- // startMessageCarousel()
153
+ startMessageCarousel()
154
154
 
155
155
  // if (item.isRead === 0) {
156
156
  // toReadFun([item.id])
@@ -0,0 +1,93 @@
1
+ <template>
2
+ <div class="notice-entry">
3
+ <img
4
+ class="notice-entry-img"
5
+ src="https://cdn.ddjf.com/static/images/loan-manage/notice-icon.png"
6
+ alt=""
7
+ />
8
+ <span>通知</span>
9
+ <div v-if="noticeShow" class="notice-entry-icon"></div>
10
+ </div>
11
+ </template>
12
+
13
+ <script lang="ts" setup>
14
+ import { onMounted, ref } from 'vue'
15
+ import { useHttp } from '../api'
16
+ import { useAppKitOptions } from '../../Appkit'
17
+ import Taro from '@tarojs/taro'
18
+
19
+ const props = withDefaults(
20
+ defineProps<{
21
+ app: string
22
+ userId: string
23
+ }>(),
24
+ {
25
+ app: '',
26
+ userId: '',
27
+ }
28
+ )
29
+
30
+ onMounted(() => {
31
+ if (!props.app) {
32
+ return Taro.showToast({
33
+ title: 'NoticeEntry组件缺少appcode',
34
+ icon: 'none',
35
+ })
36
+ }
37
+ getNotice()
38
+ })
39
+
40
+ // 通知红点
41
+ const noticeShow = ref(false)
42
+ async function getNotice() {
43
+ const appkitOptions = useAppKitOptions()
44
+ const $http = useHttp()
45
+
46
+ $http
47
+ .get('/cas/msg/count-unread', {
48
+ deviceType: 2,
49
+ appCode: props.app,
50
+ tenantId: appkitOptions.tenant(),
51
+ userId: props.userId,
52
+ })
53
+ .then((result: any) => {
54
+ if (result.status === 200) {
55
+ noticeShow.value = result.data > 0
56
+ }
57
+ })
58
+ }
59
+ </script>
60
+
61
+ <style lang="scss">
62
+ .notice-entry {
63
+ position: fixed;
64
+ right: 43px;
65
+ top: 21px;
66
+ min-width: 66px;
67
+ padding: 0 12px 0 15px;
68
+ text-align: center;
69
+ box-sizing: border-box;
70
+ height: 25px;
71
+ line-height: 11px;
72
+ color: #855f0b;
73
+ font-size: 13px;
74
+ background: #ffdf68;
75
+ border-radius: 50px 0 0 50px;
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ &-img {
80
+ width: 20px;
81
+ height: 20px;
82
+ }
83
+ &-icon {
84
+ position: absolute;
85
+ background-color: red;
86
+ width: 6px;
87
+ height: 6px;
88
+ border-radius: 50%;
89
+ top: 1px;
90
+ left: 27px;
91
+ }
92
+ }
93
+ </style>
@@ -0,0 +1,278 @@
1
+ <template>
2
+ <div class="notice-list">
3
+ <DdSearch
4
+ :bordered="false"
5
+ :focus="false"
6
+ :value="query.title"
7
+ placeholder="请输入客户姓名搜索"
8
+ @search="onSearch"
9
+ />
10
+
11
+ <div style="flex: 1; overflow: hidden">
12
+ <div class="wrapper" v-if="list.length">
13
+ <scroll-view
14
+ class="content"
15
+ :scroll-y="true"
16
+ :refresher-enabled="true"
17
+ :refresherTriggered="isRefresh"
18
+ @refresherrefresh="onRefresh"
19
+ :lower-threshold="100"
20
+ @scrolltolower="runNext"
21
+ bindscroll=""
22
+ >
23
+ <div
24
+ class="card"
25
+ :class="{ active: item.isRead != '1' }"
26
+ v-for="(item, index) in list"
27
+ :key="index"
28
+ @click="notifyRead(item, index)"
29
+ >
30
+ <div class="point"></div>
31
+ <div>
32
+ <div class="time">
33
+ {{ formatMinutes(item.receiveTime) }}
34
+ </div>
35
+ <div class="text tit" :class="{ gray: item.isRead == '1' }">
36
+ {{ item.title }}
37
+ </div>
38
+ <div class="text" :class="{ gray: item.isRead == '1' }">
39
+ <rich-text style="white-space: pre-wrap" :nodes="item.context"></rich-text>
40
+ <span
41
+ v-if="item.link && item.msgType == 3"
42
+ class="account-news-file"
43
+ @click="onNoticeView(item.link)"
44
+ >
45
+ 查看附件
46
+ </span>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ <div v-if="isLast" class="cue-text" style="padding-bottom: 40px">没有更多了</div>
51
+ </scroll-view>
52
+ </div>
53
+ <div v-else class="no-data">
54
+ <div class="no-data-img">
55
+ <img
56
+ style="width: 100%; height: 100%"
57
+ src="https://cdn.ddjf.com/static/images/loan-manage/no-data.png"
58
+ alt=""
59
+ />
60
+ </div>
61
+ <div class="text">暂无记录</div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </template>
66
+
67
+ <script lang="ts" setup>
68
+ import { onMounted, ref } from 'vue'
69
+ import Taro from '@tarojs/taro'
70
+ import DdSearch from '../../components/dd-search/index.vue'
71
+ import dayjs from 'dayjs'
72
+ import { useNotice } from './useNotice'
73
+ import { useCommonList } from './useCommonList'
74
+ import { NoticeListQueryTypes, NoticeListTypes } from '../types'
75
+ import { useAppKitOptions } from '../../Appkit'
76
+
77
+ const props = withDefaults(
78
+ defineProps<{
79
+ app: string
80
+ userId: string
81
+ }>(),
82
+ {
83
+ app: '',
84
+ userId: '',
85
+ }
86
+ )
87
+
88
+ const query = ref<any>({
89
+ pageNum: 1,
90
+ pageSize: 15,
91
+ title: '',
92
+ deviceType: 2,
93
+ })
94
+
95
+ const { toReadFun } = useNotice()
96
+ const { list, init, runNext, runRefresh, isLast } = useCommonList<
97
+ NoticeListTypes,
98
+ NoticeListQueryTypes
99
+ >('/cas/msg/queryUserMsg', query, true, 'POST')
100
+
101
+ onMounted(async () => {
102
+ if (!props.app) {
103
+ return Taro.showToast({
104
+ title: 'NoticeList组件缺少appcode',
105
+ icon: 'none',
106
+ })
107
+ }
108
+
109
+ const appkitOptions = useAppKitOptions()
110
+ query.value.appCode = props.app
111
+ query.value.tenantId = appkitOptions.tenant()
112
+ query.value.userId = props.userId
113
+ await init()
114
+ })
115
+
116
+ // 格式化时间
117
+ function formatMinutes(time: number) {
118
+ if (!time) return ''
119
+ const start = dayjs(time)
120
+ const end = dayjs()
121
+
122
+ // 使用diff方法计算差异,单位为分钟
123
+ const diffInMinutes = end.diff(start, 'minute')
124
+ if (diffInMinutes < 60 && 0 > diffInMinutes) {
125
+ return `${diffInMinutes}分钟前`
126
+ }
127
+
128
+ return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
129
+ }
130
+
131
+ // 消息读取
132
+ async function notifyRead(notice: any, index) {
133
+ if (notice.isRead == '0') {
134
+ const res = await toReadFun([notice.id])
135
+
136
+ if (res) {
137
+ list.value[index].isRead = '1'
138
+ }
139
+ }
140
+ }
141
+
142
+ // 点击搜索
143
+ function onSearch(key: string) {
144
+ delete query.value.title
145
+ query.value.content = key || ''
146
+ init()
147
+ }
148
+
149
+ // 下拉刷新
150
+ const isRefresh = ref(false)
151
+ async function onRefresh() {
152
+ isRefresh.value = true
153
+ await runRefresh()
154
+ isRefresh.value = false
155
+ }
156
+
157
+ // 查看附件
158
+ function onNoticeView(link) {
159
+ emits('view', link)
160
+ }
161
+
162
+ // 父组件事件
163
+ const emits = defineEmits(['view'])
164
+ </script>
165
+
166
+ <style lang="scss">
167
+ .notice-list {
168
+ height: 100vh;
169
+ overflow: hidden;
170
+ display: flex;
171
+ flex-direction: column;
172
+ .wrapper {
173
+ height: 100%;
174
+ padding: 10px 12px;
175
+ box-sizing: border-box;
176
+ .content {
177
+ height: 100%;
178
+ background: #ffffff;
179
+ border-radius: 10px;
180
+ .card {
181
+ margin: 0 10px;
182
+ min-height: 64px;
183
+ background: #fff;
184
+ position: relative;
185
+ padding: 10px;
186
+ &::before {
187
+ content: '';
188
+ position: absolute;
189
+ left: 2px;
190
+ top: 0;
191
+ height: 18px;
192
+ width: 1px;
193
+ background: #d8d8d8;
194
+ }
195
+ &::after {
196
+ content: '';
197
+ position: absolute;
198
+ left: 2px;
199
+ top: 18px;
200
+ bottom: 0;
201
+ width: 1px;
202
+ background: #d8d8d8;
203
+ }
204
+ &:first-child::before {
205
+ display: none;
206
+ }
207
+ &:last-child::after {
208
+ display: none;
209
+ }
210
+ .point {
211
+ width: 5px;
212
+ height: 5px;
213
+ background-color: #d8d8d8;
214
+ border-radius: 50%;
215
+ position: absolute;
216
+ left: 0;
217
+ top: 18px;
218
+ z-index: 9;
219
+ }
220
+ .time {
221
+ font-size: 13px;
222
+ color: #353535;
223
+ line-height: 19px;
224
+ opacity: 0.2;
225
+ margin-bottom: 5px;
226
+ }
227
+ .text {
228
+ font-size: 14px;
229
+ line-height: 20px;
230
+ color: #9fa0a1;
231
+ }
232
+ &.active {
233
+ .point {
234
+ background-color: #f43309;
235
+ }
236
+ .text {
237
+ color: #171a1d;
238
+ font-size: 13px;
239
+ &.tit {
240
+ font-size: 15px;
241
+ margin-bottom: 4px;
242
+ }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ .no-data {
249
+ background-color: #fff;
250
+ display: flex;
251
+ align-items: center;
252
+ flex-direction: column;
253
+ height: 100%;
254
+ .text {
255
+ height: 20px;
256
+ font-size: 14px;
257
+ color: #7e7e7e;
258
+ line-height: 20px;
259
+ }
260
+ &-img {
261
+ width: 238px;
262
+ height: 157px;
263
+ margin-top: 105px;
264
+ margin-bottom: 19px;
265
+ }
266
+ }
267
+ &-file {
268
+ font-size: 12px;
269
+ color: #017fff;
270
+ }
271
+ .cue-text {
272
+ font-size: 13px;
273
+ color: rgba(60, 60, 60, 0.5);
274
+ padding: 30px 0 calc(30px + env(safe-area-inset-bottom, 0px));
275
+ text-align: center;
276
+ }
277
+ }
278
+ </style>
@@ -1,4 +1,6 @@
1
1
  import NoticeBanner from './NoticeBanner.vue'
2
2
  import LoginSetting from './LoginSetting.vue'
3
+ import NoticeEntry from './NoticeEntry.vue'
4
+ import NoticeList from './NoticeList.vue'
3
5
 
4
- export { NoticeBanner, LoginSetting }
6
+ export { NoticeBanner, LoginSetting, NoticeEntry, NoticeList }
@@ -0,0 +1,86 @@
1
+ import Taro from '@tarojs/taro'
2
+ import { Ref, ref, unref } from 'vue'
3
+ import { useHttp } from '../api'
4
+
5
+ interface ListResponseType<T> {
6
+ total: number
7
+ pageNum: number
8
+ pageSize: number
9
+ list: Array<T>
10
+ [prop: string]: unknown
11
+ }
12
+ interface QueryLimit {
13
+ pageNum: number
14
+ pageSize: number
15
+ }
16
+
17
+ export function useCommonList<R, Q extends QueryLimit>(
18
+ api: string,
19
+ query: Ref<Q>,
20
+ showLoading = true,
21
+ method = 'GET'
22
+ ) {
23
+ const isLast = ref(false)
24
+ const list = ref<R[]>([]) as Ref<R[]>
25
+ const firstLoading = ref(true) // 是否第一次加载
26
+ const total = ref(0)
27
+ const isLoading = ref(false)
28
+
29
+ async function fetchData(loading) {
30
+ loading &&
31
+ Taro.showLoading({
32
+ title: '加载中...',
33
+ })
34
+ isLoading.value = true
35
+
36
+ const $http = useHttp()
37
+ const res = await $http[method === 'GET' ? 'get' : 'post']<ListResponseType<R>>(api, {
38
+ ...unref(query),
39
+ })
40
+
41
+ isLoading.value = false
42
+ loading && Taro.hideLoading()
43
+ if (res) {
44
+ const pages = Math.ceil(res.total / res.pageSize)
45
+ isLast.value = res.pageNum >= pages
46
+ total.value = res.total
47
+ }
48
+
49
+ return res?.list || []
50
+ }
51
+ async function runNext() {
52
+ if (isLast.value) return
53
+ if (isLoading.value) return
54
+ query.value.pageNum += 1
55
+ const data = await fetchData(true)
56
+ list.value.push(...data)
57
+ }
58
+ async function runRefresh() {
59
+ query.value.pageNum = 1
60
+ isLast.value = false
61
+ const data = await fetchData(true)
62
+ if (data.length === 0) {
63
+ list.value = []
64
+ } else {
65
+ list.value = data // 直接替换,避免白屏
66
+ }
67
+ }
68
+
69
+ async function init(pageNum?: number) {
70
+ query.value.pageNum = pageNum || 1
71
+ isLast.value = false
72
+ const data = await fetchData(showLoading)
73
+ list.value = data || []
74
+ firstLoading.value = false
75
+ }
76
+
77
+ return {
78
+ total,
79
+ isLast,
80
+ firstLoading,
81
+ list,
82
+ init,
83
+ runNext,
84
+ runRefresh,
85
+ }
86
+ }
@@ -0,0 +1,25 @@
1
+ // 消息
2
+ export interface NoticeListQueryTypes {
3
+ pageNum: number
4
+ pageSize: number
5
+ searchStr: string
6
+ }
7
+
8
+ // 消息内容
9
+ export interface Notice {
10
+ applyNo: string // 消息关联订单编号 string
11
+ customerId: string // 消息关联客户编号 string
12
+ id: number // id integer(int64)
13
+ isRead: string // 是否已读(0:未读;1:已读) string
14
+ msg: string // 消息内容 string
15
+ msgType: string // 消息主体类型(order:订单;customer:客户) string
16
+ sendTime: string // 消息发送时间
17
+ [props: string]: any
18
+ }
19
+
20
+ // 消息列表
21
+ export interface NoticeListTypes {
22
+ list: Notice[]
23
+ total: number | string
24
+ [props: string]: any
25
+ }
@@ -28,7 +28,7 @@ async function getPropertieByCode() {
28
28
  if (recommendVersions.value) return
29
29
 
30
30
  const $http = useHttp()
31
- await $http
31
+ $http
32
32
  .get('/cas/properties/getPropertie', {
33
33
  code: 'pcRecommendVersion',
34
34
  })