lxui-uni 0.0.2 → 0.0.3

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/theme.scss ADDED
@@ -0,0 +1,228 @@
1
+ /*============================= 文字尺寸 =============================*/
2
+ $font-size-20: 20rpx;
3
+ $font-size-22: 22rpx;
4
+ $font-size-24: 24rpx;
5
+ $font-size-26: 26rpx;
6
+ $font-size-28: 28rpx;
7
+ $font-size-30: 30rpx;
8
+ $font-size-32: 32rpx;
9
+ $font-size-34: 34rpx;
10
+ $font-size-36: 36rpx;
11
+ $font-size-38: 38rpx;
12
+ $font-size-40: 40rpx;
13
+ // 主题颜色
14
+ $main-color: #ff8d1a;
15
+
16
+ image {
17
+ width: 100%;
18
+ height: 100%;
19
+ }
20
+
21
+ @mixin btn-line {
22
+ font-size: $font-size-32;
23
+ color: $main-color;
24
+ padding: 16rpx 26rpx;
25
+ border: 2rpx solid $main-color;
26
+ text-align: center;
27
+ border-radius: 180rpx;
28
+ box-sizing: border-box;
29
+ }
30
+
31
+ @mixin btn-solid {
32
+ font-size: $font-size-32;
33
+ color: #fff;
34
+ background-color: $main-color;
35
+ padding: 16rpx 26rpx;
36
+ border: 2rpx solid $main-color;
37
+ text-align: center;
38
+ border-radius: 8rpx;
39
+ box-sizing: border-box;
40
+ }
41
+
42
+ // 间隔线
43
+ .line_box {
44
+ width: 100%;
45
+ height: 16rpx;
46
+ background-color: #f2f2f2;
47
+ }
48
+
49
+
50
+
51
+ // 弹框公用
52
+ .dialog_content_lx {
53
+ .dialog_icon_lx {
54
+ margin: 0 auto;
55
+ width: 116rpx;
56
+ height: 116rpx;
57
+ }
58
+
59
+ .dialog_txt_lx {
60
+ text-align: center;
61
+ margin-top: 20rpx;
62
+ font-size: $font-size-34;
63
+ color: rgba(0, 0, 0, 1);
64
+ }
65
+ }
66
+
67
+ .dialog_sub_btns_lx {
68
+ padding: 0 36rpx;
69
+
70
+ .dialog_submit_btn_lx {
71
+ @include btn-line;
72
+ background-color: $main-color;
73
+ color: #fff;
74
+ margin-bottom: 20rpx;
75
+ }
76
+
77
+ .dialog_cancel_btn_lx {
78
+ @include btn-line;
79
+ color: rgba(128, 128, 128, 1);
80
+ border-color: rgba(128, 128, 128, 1);
81
+ }
82
+ }
83
+
84
+ // 弹框公用
85
+
86
+ /*============================= 弹性盒子 =============================*/
87
+ @mixin displayFlex($align: center, $justify: center) {
88
+ display: flex;
89
+ flex-wrap: nowrap;
90
+ flex-direction: row;
91
+ align-items: $align;
92
+ justify-content: $justify;
93
+ }
94
+
95
+ @mixin alignItems($align: center) {
96
+ @include displayFlex($align, center);
97
+
98
+ &-start {
99
+ @include displayFlex($align, flex-start);
100
+ }
101
+
102
+ &-center {
103
+ @include displayFlex($align, center);
104
+ }
105
+
106
+ &-end {
107
+ @include displayFlex($align, flex-end);
108
+ }
109
+
110
+ &-between {
111
+ @include displayFlex($align, space-between);
112
+ }
113
+
114
+ &-around {
115
+ @include displayFlex($align, space-around);
116
+ }
117
+
118
+ &-evenly {
119
+ @include displayFlex($align, space-evenly);
120
+ }
121
+ }
122
+
123
+ .flex {
124
+ @include displayFlex;
125
+
126
+ &-center {
127
+ @include alignItems(center);
128
+ }
129
+
130
+ &-start {
131
+ @include alignItems(flex-start);
132
+ }
133
+
134
+ &-end {
135
+ @include alignItems(flex-end);
136
+ }
137
+ }
138
+
139
+ /* #ifdef MP-TOUTIAO */
140
+ .row {
141
+ flex-direction: row;
142
+ }
143
+
144
+ .row-reverse {
145
+ flex-direction: row-reverse;
146
+ }
147
+
148
+ .column {
149
+ flex-direction: column;
150
+ }
151
+
152
+ .column-reverse {
153
+ flex-direction: column-reverse;
154
+ }
155
+
156
+ .wrap {
157
+ flex-wrap: wrap;
158
+ }
159
+
160
+ .nowrap {
161
+ flex-wrap: nowrap;
162
+ }
163
+ /* #endif */
164
+
165
+ [class*="flex-"],
166
+ [class^="flex"] {
167
+ &.row {
168
+ flex-direction: row;
169
+ }
170
+
171
+ &.row-reverse {
172
+ flex-direction: row-reverse;
173
+ }
174
+
175
+ &.column {
176
+ flex-direction: column;
177
+ }
178
+
179
+ &.column-reverse {
180
+ flex-direction: column-reverse;
181
+ }
182
+
183
+ &.wrap {
184
+ flex-wrap: wrap;
185
+ }
186
+
187
+ &.nowrap {
188
+ flex-wrap: nowrap;
189
+ }
190
+ }
191
+
192
+ // 生成flex1等占位
193
+ @for $i from 1 through 5 {
194
+ .flex#{$i} {
195
+ flex: #{$i};
196
+ }
197
+ }
198
+
199
+ /*============================= 文字溢出 =============================*/
200
+
201
+ %text-ellipsis-lint {
202
+ text-overflow: ellipsis;
203
+ white-space: normal;
204
+ display: -webkit-box;
205
+ -webkit-box-orient: vertical;
206
+ overflow: hidden;
207
+ }
208
+
209
+ .text-ellipsis {
210
+ --line: 1;
211
+ @extend %text-ellipsis-lint;
212
+ -webkit-line-clamp: var(--line);
213
+
214
+ &-1 {
215
+ @extend %text-ellipsis-lint;
216
+ -webkit-line-clamp: 1;
217
+ }
218
+
219
+ &-2 {
220
+ @extend %text-ellipsis-lint;
221
+ -webkit-line-clamp: 2;
222
+ }
223
+
224
+ &-3 {
225
+ @extend %text-ellipsis-lint;
226
+ -webkit-line-clamp: 3;
227
+ }
228
+ }
@@ -0,0 +1,23 @@
1
+ import lxHeader from '../components/lx-header/lx-header.vue'
2
+ import lxHello from '../components/lx-hello/lx-hello.vue'
3
+ import lxImage from '../components/lx-image/lx-image.vue'
4
+ import lxList from '../components/lx-list/lx-list.vue'
5
+ import lxListState from '../components/lx-list-state/lx-list-state.vue'
6
+ import lxOperateBottom from '../components/lx-operate-bottom/lx-operate-bottom.vue'
7
+ import lxSubmitBtn from '../components/lx-submit-btn/lx-submit-btn.vue'
8
+ import lxUpload from '../components/lx-upload/lx-upload.vue'
9
+
10
+
11
+ declare module 'vue' {
12
+ export interface GlobalComponents {
13
+ "lx-header": typeof lxHeader,
14
+ "lx-hello": typeof lxHello,
15
+ "lx-image": typeof lxImage,
16
+ "lx-list": typeof lxList,
17
+ "lx-list-state": typeof lxListState,
18
+ "lx-operate-bottom": typeof lxOperateBottom,
19
+ "lx-submit-btn": typeof lxSubmitBtn,
20
+ "lx-upload": typeof lxUpload,
21
+ }
22
+ }
23
+
package/util/index.ts ADDED
@@ -0,0 +1,294 @@
1
+ /**
2
+ * 公共跳转方法
3
+ * @author liux
4
+ * @date 2023-08-15 14:17
5
+ * @param { string } url 跳转路径
6
+ * @param { "navigateTo" | "redirectTo" | "reLaunch" | "switchTab" } [mode=navigateTo] 跳转模式
7
+ * @param { object } params 跳转传参
8
+ * @example
9
+ * goToPage({ url: 'pages/index/index', mode: 'navigateTo', params: {'id': 1} })
10
+ * @returns { void }
11
+ */
12
+ type pageMode = 'navigateTo' | 'redirectTo' | 'reLaunch' | 'switchTab'
13
+
14
+ interface goToPageInt {
15
+ url: string
16
+ mode?: pageMode
17
+ params?: {
18
+ [n: string]: string | number | boolean
19
+ }
20
+ }
21
+
22
+ export const goToPage = ({ url, mode = 'navigateTo', params = {} }: goToPageInt): void => {
23
+ if (!url || url.length === 0) {
24
+ throw Error('"url" is a required parameter')
25
+ }
26
+
27
+ const urlEncode = (params: any = {}) => {
28
+ const result :string[] = []
29
+ for (const k in params) {
30
+ if (!params[k]) continue
31
+ result.push(k + '=' + params[k])
32
+ }
33
+
34
+ return result.join('&')
35
+ }
36
+ // const storage = JSON.parse(uni.getStorageSync('LX_user'))
37
+ // const token = storage?.userInfo?.token
38
+ // if(!token) {
39
+ // url = 'pages/login/loginXcx'
40
+ // mode = 'navigateTo'
41
+ // }
42
+ const queryStr = !isEmpty(params) ? '?' + urlEncode(params) : ''
43
+ const obj = { url: `/${url}${queryStr}` }
44
+ console.log('obj', obj)
45
+ switch (mode) {
46
+ case 'navigateTo':
47
+ uni.navigateTo(obj)
48
+ break
49
+ case 'redirectTo':
50
+ uni.redirectTo(obj)
51
+ break
52
+ case 'reLaunch':
53
+ uni.reLaunch(obj)
54
+ break
55
+ case 'switchTab':
56
+ uni.switchTab(obj)
57
+ break
58
+ default:
59
+ throw Error(`${mode} does not exist`)
60
+ }
61
+ }
62
+
63
+ /**
64
+ * 判断是否为空对象
65
+ * @author liux
66
+ * @date 2023-08-15 14:17
67
+ * @license MIT
68
+ * @param {*} object 源对象
69
+ * @returns { boolean }
70
+ */
71
+ export const isEmptyObject = (object: any): boolean => {
72
+ return Object.keys(object).length === 0
73
+ }
74
+
75
+ /**
76
+ * 判断是否为对象
77
+ * @author liux
78
+ * @date 2023-08-15 14:17
79
+ * @license MIT
80
+ * @param {*} object 源对象
81
+ * @returns { boolean }
82
+ */
83
+ export const isObject = (object: any): boolean => {
84
+ return Object.prototype.toString.call(object) === '[object Object]'
85
+ }
86
+
87
+ /**
88
+ * 判断是否为数组
89
+ * @author liux
90
+ * @license MIT
91
+ * @param {*} object 源对象
92
+ * @returns { boolean }
93
+ */
94
+ export const isArray = (object: any): boolean => {
95
+ return Object.prototype.toString.call(object) === '[object Array]'
96
+ }
97
+
98
+ /**
99
+ * 判断是否为空
100
+ * @author liux
101
+ * @license MIT
102
+ * @param {*} value 源对象
103
+ * @returns { boolean }
104
+ */
105
+ export const isEmpty = (value: any): boolean => {
106
+ if (isArray(value)) {
107
+ return value.length === 0
108
+ }
109
+ if (isObject(value)) {
110
+ return isEmptyObject(value)
111
+ }
112
+ return !value
113
+ }
114
+
115
+ /**
116
+ * 格式化时间戳(多格式)
117
+ * @author liux
118
+ * @license MIT
119
+ * @param { number } time 长度为 10 | 13 的时间戳
120
+ * @param { string } [format=yyyy-MM-dd] format 转换格式
121
+ * @example
122
+ * formatTime(1691744378556, 'yyyy-MM-dd HH:mm:ss')
123
+ * @returns { string }
124
+ */
125
+
126
+ export const formatTime = (time: number, format: string = 'yyyy-MM-dd HH:mm:ss'): string => {
127
+ const len = time.toString().trim().length
128
+ if (len !== 10 && len !== 13) {
129
+ throw Error('"time" is a error parameter')
130
+ }
131
+
132
+ time = len !== 13 ? time * 1000 : time
133
+
134
+ if (!time) return ''
135
+ const date = new Date(time)
136
+ const M = (date.getMonth() + 1).toString()
137
+ const d = date.getDate().toString()
138
+ const H = date.getHours().toString()
139
+ const m = date.getMinutes().toString()
140
+ const s = date.getSeconds().toString()
141
+ const timeObject: {
142
+ [n: string]: string
143
+ } = {
144
+ yyyy: date.getFullYear().toString(),
145
+ MM: M.padStart(2, '0'),
146
+ dd: d.padStart(2, '0'),
147
+ HH: H.padStart(2, '0'),
148
+ mm: m.padStart(2, '0'),
149
+ ss: s.padStart(2, '0'),
150
+ M: M,
151
+ d: d,
152
+ H: H,
153
+ m: m,
154
+ s: s
155
+ }
156
+ const reg = new RegExp(Object.keys(timeObject).join('|'), 'g')
157
+ const res = format.replace(reg, (k) => {
158
+ return timeObject[k]
159
+ })
160
+ return res
161
+ }
162
+
163
+ // 判断当前时间是否在一个时间区间内
164
+ export const isTimeIn = (start: string, end: string) => {
165
+ // 获取当前时间
166
+ const currentTime = new Date()
167
+ const startArr = start.split(':').map(Number)
168
+ // 设置开始时间为10:00
169
+ const startTime = new Date()
170
+ startTime.setHours(startArr[0], startArr[1])
171
+
172
+ // 设置结束时间为20:00
173
+ const endArr = end.split(':').map(Number)
174
+ const endTime = new Date()
175
+ endTime.setHours(endArr[0], endArr[1])
176
+
177
+ // 检查当前时间是否在10:00到20:00之间
178
+ if (currentTime >= startTime && currentTime <= endTime) {
179
+ // console.log('当前时间在之间')
180
+ } else {
181
+ // console.log('当前时间不在之间')
182
+ }
183
+ }
184
+
185
+ /**
186
+ * 防抖函数
187
+ * @author liux
188
+ * @license MIT
189
+ * @param {function} fn
190
+ * @param {umber} [wait=1000] wait
191
+ * @returns { void }
192
+ */
193
+ export const debounce = <T extends (...args: any[]) => any>(fn: T, wait: number = 1000): ((...args: Parameters<T>) => void) => {
194
+ let timer: number | null
195
+
196
+ return function (this: any, ...args: Parameters<T>) {
197
+ if (timer) clearTimeout(timer)
198
+
199
+ timer = setTimeout(() => {
200
+ fn.apply(this, args)
201
+ }, wait)
202
+ }
203
+ }
204
+
205
+ /**
206
+ * 节流函数
207
+ * @author liux
208
+ * @date 2023-08-15 14:17
209
+ * @license MIT
210
+ * @param { function } fn
211
+ * @param { number } [wait=1000] wait
212
+ */
213
+ export const throttle = <T extends (...args: any[]) => any>(fn: T, wait: number = 1000) => {
214
+ let timer: number = Date.now()
215
+ return function (this: any, ...args: Parameters<T>) {
216
+ if (Date.now() - timer >= wait) {
217
+ fn.apply(this, args)
218
+ timer = Date.now()
219
+ }
220
+ }
221
+ }
222
+
223
+ /**
224
+ * 保存图片到本地
225
+ * @author liux
226
+ * @param { string } url 需要下载的图片
227
+ * @example
228
+ * saveImgData('/upload/images/img.png')
229
+ * @returns
230
+ */
231
+ export const saveImgData = debounce((url: string) => {
232
+ uni.showLoading({ title: '图片保存中...', mask: true })
233
+ // 判断图片地址是否有http
234
+ if (url.indexOf('http') === -1) {
235
+ url = import.meta.env.VITE_APP_BASE_URL + url
236
+ }
237
+ uni.downloadFile({
238
+ url,
239
+ success: (res: any) => {
240
+ if (res.statusCode === 200) {
241
+ uni.saveImageToPhotosAlbum({
242
+ filePath: res.tempFilePath,
243
+ success: () => {
244
+ uni.showToast({
245
+ title: '保存成功~',
246
+ icon: 'none',
247
+ duration: 2000
248
+ })
249
+ },
250
+ fail: () => {
251
+ uni.showToast({
252
+ title: '保存失败~',
253
+ icon: 'none',
254
+ duration: 2000
255
+ })
256
+ },
257
+ complete: () => {
258
+ uni.hideLoading()
259
+ }
260
+ })
261
+ }
262
+ }
263
+ })
264
+ })
265
+
266
+ /**
267
+ * 设置剪贴板
268
+ * @author liux
269
+ * @param { string } data 需要复制的内容
270
+ * @example
271
+ * setClipboardData('123456')
272
+ * @returns
273
+ */
274
+ export const setClipboardData = (data: string) => {
275
+ uni.setClipboardData({
276
+ data: data,
277
+ success: () => {
278
+ uni.showToast({
279
+ title: '复制成功',
280
+ icon: 'none',
281
+ duration: 2000
282
+ })
283
+ }
284
+ })
285
+ }
286
+
287
+ export default {
288
+ goToPage,
289
+ formatTime,
290
+ debounce,
291
+ throttle,
292
+ saveImgData,
293
+ setClipboardData
294
+ }
@@ -0,0 +1,143 @@
1
+ /*
2
+ * @description: 分页请求
3
+ * @fileName: useListLoadClass.ts
4
+ * @author: lxx
5
+ * @date: 2023-07-08 08:55:52
6
+ * @version: V1.0.0
7
+ */
8
+ import { reactive, ref, computed } from "vue"
9
+ class LoadDataClass {
10
+ // 请求参数
11
+ static queryParams = reactive({
12
+ page: 1,
13
+ limit: 10
14
+ })
15
+ // 列表数据
16
+ list = ref<any[]>([])
17
+ total = ref(0)
18
+ // 前置处理方法
19
+ afterLoadData: Function | undefined
20
+ // 请求方法
21
+ Query: Function
22
+ // 加载状态参数
23
+ isLoading = ref(false)
24
+ // 无更多数据了
25
+ isNoData = computed(() => {
26
+ if (LoadDataClass.queryParams.page * LoadDataClass.queryParams.limit >= this.total.value) {
27
+ return true
28
+ } else {
29
+ return false
30
+ }
31
+ })
32
+ // 显示暂无数据
33
+ isEmpty = computed(() => {
34
+ if (this.total.value === 0) {
35
+ return true
36
+ } else {
37
+ return false
38
+ }
39
+ })
40
+
41
+ constructor(apiFunctions: Function, afterLoadData?: Function, options: any = {}) {
42
+ this.queryParamsReset()
43
+ this.Query = apiFunctions
44
+ this.afterLoadData = afterLoadData
45
+ // console.log('options', options)
46
+ // 存在额外参数拼接
47
+ this.setParams(options)
48
+ }
49
+ // 加载数据
50
+ LoadData = async () => {
51
+ uni.showLoading({
52
+ title: '加载中...'
53
+ })
54
+ this.isLoading.value = true
55
+ const res = await this.Query(LoadDataClass.queryParams)
56
+ this.afterLoadData && this.afterLoadData(res)
57
+ this.total.value = res.data.total
58
+ this.list.value = this.list.value.concat(res.data.items)
59
+
60
+ uni.hideLoading()
61
+ uni.stopPullDownRefresh()
62
+ this.isLoading.value = false
63
+ }
64
+ /**
65
+ * 添加额外参数刷新
66
+ * @param options: 参数
67
+ * @param isClear: 是否清空数据 false
68
+ */
69
+ setParams = (options: any, isClear: boolean = false) => {
70
+ if (isClear) {
71
+ this.queryParamsReset()
72
+ } else {
73
+ LoadDataClass.queryParams.page = 1
74
+ }
75
+ this.list.value = []
76
+ LoadDataClass.queryParams = Object.assign(LoadDataClass.queryParams, options)
77
+ // 加载数据
78
+ this.LoadData()
79
+ }
80
+ // 加载更多
81
+ LoadMore = () => {
82
+ if (this.isNoData.value || this.isLoading.value) return // 无数据或者加载中不进行加载
83
+ LoadDataClass.queryParams.page += 1
84
+ this.LoadData()
85
+ }
86
+ // 重置参数
87
+ queryParamsReset = () => {
88
+ LoadDataClass.queryParams = reactive({
89
+ page: 1,
90
+ limit: 10
91
+ })
92
+ }
93
+
94
+ /**
95
+ * 刷新
96
+ * @param isClear: 是否清空数据
97
+ */
98
+ ReLoad = (isClear: boolean = false) => {
99
+ this.isLoading.value = false
100
+ this.list.value = []
101
+ if (isClear) {
102
+ this.queryParamsReset()
103
+ } else {
104
+ LoadDataClass.queryParams.page = 1
105
+ }
106
+ this.LoadData()
107
+ }
108
+ }
109
+ /**
110
+ * 分页加载数据方法
111
+ * @param api: ListAPI 方法
112
+ * @param afterLoadData: res数据前置处理方法
113
+ * @returns
114
+ */
115
+ interface LoadDataInt {
116
+ api: Function
117
+ afterLoadData?: Function
118
+ options?: any
119
+ isNeedReachBottom?: boolean
120
+ }
121
+
122
+ export function LoadData({ api, afterLoadData, options, isNeedReachBottom = true }: LoadDataInt) {
123
+ const data = new LoadDataClass(api, afterLoadData, options)
124
+
125
+ // 下拉加载
126
+ if (isNeedReachBottom) {
127
+ onReachBottom(() => {
128
+ console.log('onReachBottom')
129
+ data.LoadMore()
130
+ })
131
+ }
132
+
133
+ return {
134
+ list: data.list,
135
+ isLoading: data.isLoading,
136
+ isNoData: data.isNoData,
137
+ isEmpty: data.isEmpty,
138
+ ReLoad: data.ReLoad,
139
+ setParams: data.setParams,
140
+ LoadMore: data.LoadMore
141
+ }
142
+ }
143
+
package/vite.config.ts ADDED
@@ -0,0 +1 @@
1
+ {}