@uxda/appkit 4.0.12 → 4.0.16

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/dist/appkit.css CHANGED
@@ -589,6 +589,7 @@ page {
589
589
  display: flex;
590
590
  flex-direction: column;
591
591
  width: 100%;
592
+ position: relative;
592
593
  }
593
594
  .consumption-date-filter .date-filter-header {
594
595
  text-align: center;
@@ -1112,13 +1113,12 @@ page {
1112
1113
  height: 12px;
1113
1114
  margin-left: 4px;
1114
1115
  }
1115
- .consumption-filter {
1116
- height: 100%;
1116
+ .list-filter-picker {
1117
1117
  display: flex;
1118
1118
  flex-direction: column;
1119
1119
  width: 100%;
1120
1120
  }
1121
- .consumption-filter-title {
1121
+ .list-filter-picker-title {
1122
1122
  position: relative;
1123
1123
  height: 44px;
1124
1124
  line-height: 44px;
@@ -1127,42 +1127,42 @@ page {
1127
1127
  background: #f5f5f5;
1128
1128
  text-align: center;
1129
1129
  }
1130
- .consumption-filter-content {
1130
+ .list-filter-picker-content {
1131
1131
  flex: 1;
1132
1132
  margin: 15px;
1133
1133
  overflow-y: scroll;
1134
1134
  color: #353535;
1135
1135
  font-size: 13px;
1136
1136
  }
1137
- .consumption-filter-content .title {
1137
+ .list-filter-picker-content .title {
1138
1138
  opacity: 0.6;
1139
1139
  line-height: 18px;
1140
1140
  }
1141
- .consumption-filter-content .info {
1141
+ .list-filter-picker-content .info {
1142
1142
  display: grid;
1143
1143
  grid-template-columns: 1fr 1fr 1fr;
1144
1144
  grid-gap: 10px;
1145
1145
  margin: 10px 0;
1146
1146
  }
1147
- .consumption-filter-content .info-item {
1147
+ .list-filter-picker-content .info-item {
1148
1148
  height: 30px;
1149
1149
  line-height: 30px;
1150
1150
  border: 1px solid #ccc;
1151
1151
  border-radius: 6px;
1152
1152
  text-align: center;
1153
1153
  }
1154
- .consumption-filter-content .info .current {
1154
+ .list-filter-picker-content .info .current {
1155
1155
  border-radius: 5px;
1156
1156
  border: 1px solid #EFD082;
1157
1157
  background: linear-gradient(180deg, #FFF7E3 0%, #FEFDE6 100%);
1158
1158
  }
1159
- .consumption-filter-btn {
1159
+ .list-filter-picker-btn {
1160
1160
  margin: 0 15px;
1161
1161
  display: flex;
1162
1162
  justify-content: space-between;
1163
1163
  align-items: center;
1164
1164
  }
1165
- .consumption-filter-btn .btn {
1165
+ .list-filter-picker-btn .btn {
1166
1166
  flex: 1;
1167
1167
  height: 40px;
1168
1168
  line-height: 40px;
@@ -1173,17 +1173,17 @@ page {
1173
1173
  font-size: 16px;
1174
1174
  border-radius: 6px;
1175
1175
  }
1176
- .consumption-filter-btn .confirm {
1176
+ .list-filter-picker-btn .confirm {
1177
1177
  margin-left: 11px;
1178
1178
  color: #000;
1179
1179
  border: none;
1180
1180
  background: linear-gradient(90deg, #ffebc1 0%, #ffd7a7 52.29%, #ffb875 100%);
1181
1181
  }
1182
- .consumption-filter-bottom {
1182
+ .list-filter-picker-bottom {
1183
1183
  height: 32px;
1184
1184
  background: #fff;
1185
1185
  }
1186
- .consumption-filter .icon {
1186
+ .list-filter-picker .icon {
1187
1187
  display: block;
1188
1188
  width: 20px;
1189
1189
  height: 20px;
@@ -1191,7 +1191,7 @@ page {
1191
1191
  background-repeat: no-repeat;
1192
1192
  background-position: center center;
1193
1193
  }
1194
- .consumption-filter .icon.icon-x {
1194
+ .list-filter-picker .icon.icon-x {
1195
1195
  position: absolute;
1196
1196
  right: 10px;
1197
1197
  top: 11px;
@@ -1705,6 +1705,10 @@ page {
1705
1705
  font-size: 15px;
1706
1706
  line-height: 21px;
1707
1707
  }
1708
+ .user-entry-bd-arrow {
1709
+ font-size: 12px;
1710
+ margin-left: 8px;
1711
+ }
1708
1712
  .dd-skeleton__item {
1709
1713
  margin-top: 10px;
1710
1714
  }
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { GridItem, Grid, Popup, Checkbox, Button, Dialog, DatePicker, Radio, RadioGroup, FormItem, Form, Skeleton, Cell, Input, Step, Steps } from '@nutui/nutui-taro';
2
2
  import '@nutui/nutui-taro/dist/packages/button/style/css';
3
3
  import '@nutui/nutui-taro/dist/packages/checkbox/style/css';
4
- import { defineComponent, reactive, openBlock, createBlock, withCtx, createElementBlock, Fragment, renderList, normalizeClass, createElementVNode, toDisplayString, createTextVNode, createStaticVNode, ref, computed, onUnmounted, createCommentVNode, renderSlot, createVNode, unref, isRef, normalizeStyle, onMounted, watch, resolveComponent, withDirectives, vShow, vModelText, watchPostEffect, withModifiers } from 'vue';
4
+ import { defineComponent, reactive, openBlock, createBlock, withCtx, createElementBlock, Fragment, renderList, normalizeClass, createElementVNode, toDisplayString, createTextVNode, createStaticVNode, ref, computed, onUnmounted, createCommentVNode, renderSlot, createVNode, unref, isRef, normalizeStyle, onMounted, watch, resolveComponent, withDirectives, vShow, useModel, mergeModels, vModelText, watchPostEffect, withModifiers } from 'vue';
5
5
  import '@nutui/nutui-taro/dist/packages/grid/style/css';
6
6
  import '@nutui/nutui-taro/dist/packages/griditem/style/css';
7
7
  import '@nutui/nutui-taro/dist/packages/popup/style/css';
@@ -291,6 +291,44 @@ const useUpload = (config) => {
291
291
  };
292
292
  };
293
293
 
294
+ const defaultCryptoConfig = {
295
+ maskField: "mask",
296
+ secretField: "secretKey"
297
+ };
298
+ function useCrypto(config) {
299
+ const parse = (data, key) => {
300
+ let k = key || "masked";
301
+ let result = {};
302
+ try {
303
+ result = JSON.parse(data);
304
+ result = {
305
+ [k]: result.mask,
306
+ // 字段后加$表示用于解密的 secret
307
+ [`${k}$`]: result.secretKey
308
+ };
309
+ } catch (e) {
310
+ }
311
+ return result;
312
+ };
313
+ const resolve = (list, field) => {
314
+ const [first] = list, f = field ? Array.isArray(field) ? field : [field] : Object.entries(first).filter(([_, v]) => /^\{.*\}$/.test(v)).map(([k]) => k);
315
+ return list.map((item) => {
316
+ let result = { ...item };
317
+ f.forEach((r) => {
318
+ result = {
319
+ ...result,
320
+ ...parse(item[r], r)
321
+ };
322
+ });
323
+ return result;
324
+ });
325
+ };
326
+ return {
327
+ parse,
328
+ resolve
329
+ };
330
+ }
331
+
294
332
  const _hoisted_1$C = {
295
333
  key: 0,
296
334
  class: "page-title"
@@ -400,16 +438,19 @@ var script$D = /* @__PURE__ */ defineComponent({
400
438
  props: {
401
439
  phone: { type: String, required: true },
402
440
  title: { type: String, required: false },
403
- message: { type: String, required: false }
441
+ message: { type: String, required: false },
442
+ onSend: { type: Function, required: false }
404
443
  },
405
- emits: ["update:modelValue"],
444
+ emits: ["complete", "cancel"],
406
445
  setup(__props, { emit: __emit }) {
446
+ const emits = __emit;
407
447
  const sent = ref(false), countdown = ref(60);
408
448
  let formData = reactive({
409
449
  code: ""
410
450
  });
411
451
  const send = () => {
412
452
  sent.value = true;
453
+ props.onSend && props.onSend();
413
454
  countdown.value = 60;
414
455
  let timer = setInterval(() => {
415
456
  countdown.value--;
@@ -419,6 +460,10 @@ var script$D = /* @__PURE__ */ defineComponent({
419
460
  }
420
461
  }, 1e3);
421
462
  };
463
+ const onOk = () => {
464
+ emits("complete", { code: formData.code });
465
+ };
466
+ const props = __props;
422
467
  return (_ctx, _cache) => {
423
468
  return openBlock(), createElementBlock("div", _hoisted_1$A, [
424
469
  createElementVNode(
@@ -444,17 +489,19 @@ var script$D = /* @__PURE__ */ defineComponent({
444
489
  ),
445
490
  createVNode(unref(NsForm), {
446
491
  modelValue: unref(formData),
447
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(formData) ? formData.value = $event : formData = $event)
492
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => isRef(formData) ? formData.value = $event : formData = $event)
448
493
  }, {
449
494
  default: withCtx(() => [
450
495
  createVNode(unref(NsInput), {
451
496
  name: "code",
497
+ modelValue: unref(formData).code,
498
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => unref(formData).code = $event),
452
499
  placeholder: "\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801",
453
500
  variant: "solid",
454
501
  rules: ["required", {
455
502
  name: "function",
456
503
  message: "\u8F93\u5165\u9519\u8BEF, \u8BF7\u91CD\u65B0\u8F93\u5165",
457
- method: (value) => value.length === 4
504
+ method: (value) => value.length === 6
458
505
  }]
459
506
  }, {
460
507
  append: withCtx(() => [
@@ -476,13 +523,16 @@ var script$D = /* @__PURE__ */ defineComponent({
476
523
  ]),
477
524
  _: 1
478
525
  /* STABLE */
479
- }, 8, ["rules"])
526
+ }, 8, ["modelValue", "rules"])
480
527
  ]),
481
528
  _: 1
482
529
  /* STABLE */
483
530
  }, 8, ["modelValue"]),
484
531
  createElementVNode("div", _hoisted_5$h, [
485
- createVNode(unref(NsButton), { round: "" }, {
532
+ createVNode(unref(NsButton), {
533
+ round: "",
534
+ onClick: _cache[2] || (_cache[2] = ($event) => emits("cancel"))
535
+ }, {
486
536
  default: withCtx(() => [
487
537
  createTextVNode("\u53D6\u6D88")
488
538
  ]),
@@ -491,7 +541,8 @@ var script$D = /* @__PURE__ */ defineComponent({
491
541
  }),
492
542
  createVNode(unref(NsButton), {
493
543
  round: "",
494
- gradient: "#FFEBC1,#FFD7A7,#FFB875/90"
544
+ gradient: "#FFEBC1,#FFD7A7,#FFB875/90",
545
+ onClick: onOk
495
546
  }, {
496
547
  default: withCtx(() => [
497
548
  createTextVNode("\u786E\u8BA4")
@@ -1929,7 +1980,7 @@ var script$v = /* @__PURE__ */ defineComponent({
1929
1980
 
1930
1981
  script$v.__file = "src/balance/components/BalanceCard.vue";
1931
1982
 
1932
- const consumptionTypes$1 = [
1983
+ const consumptionTypes = [
1933
1984
  "\u5168\u90E8",
1934
1985
  "\u5145\u503C",
1935
1986
  "\u7F34\u8D39",
@@ -1941,8 +1992,8 @@ const consumptionTypes$1 = [
1941
1992
  "\u8D60\u9001",
1942
1993
  "\u6362\u8D2D"
1943
1994
  ];
1944
- const consumptionPositions$1 = ["\u5168\u90E8", "\u4E91\u8C46", "\u6743\u76CA"];
1945
- const consumptionDirections$1 = ["\u5168\u90E8", "\u6536\u5165", "\u652F\u51FA"];
1995
+ const consumptionPositions = ["\u5168\u90E8", "\u4E91\u8C46", "\u6743\u76CA"];
1996
+ const consumptionDirections = ["\u5168\u90E8", "\u6536\u5165", "\u652F\u51FA"];
1946
1997
 
1947
1998
  const _hoisted_1$t = { class: "consumption-filter" };
1948
1999
  const _hoisted_2$p = /* @__PURE__ */ createElementVNode(
@@ -1979,15 +2030,15 @@ var script$u = /* @__PURE__ */ defineComponent({
1979
2030
  const filterSections = ref([
1980
2031
  {
1981
2032
  title: "\u7C7B\u578B",
1982
- data: consumptionPositions$1.map((s) => ({ code: s, name: s }))
2033
+ data: consumptionPositions.map((s) => ({ code: s, name: s }))
1983
2034
  },
1984
2035
  {
1985
2036
  title: "\u6536\u5165/\u652F\u51FA",
1986
- data: consumptionDirections$1.map((s) => ({ code: s, name: s }))
2037
+ data: consumptionDirections.map((s) => ({ code: s, name: s }))
1987
2038
  },
1988
2039
  {
1989
2040
  title: "\u660E\u7EC6\u7C7B\u578B",
1990
- data: consumptionTypes$1.map((s) => ({ code: s, name: s }))
2041
+ data: consumptionTypes.map((s) => ({ code: s, name: s }))
1991
2042
  },
1992
2043
  {
1993
2044
  title: "\u6743\u76CA\u7C7B\u76EE",
@@ -2165,74 +2216,66 @@ var script$t = /* @__PURE__ */ defineComponent({
2165
2216
  return (_ctx, _cache) => {
2166
2217
  const _component_nut_date_picker = DatePicker;
2167
2218
  const _component_nut_popup = Popup;
2168
- return openBlock(), createElementBlock(
2169
- Fragment,
2170
- null,
2171
- [
2172
- createElementVNode("div", _hoisted_1$s, [
2173
- _hoisted_2$o,
2174
- createElementVNode("div", _hoisted_3$j, [
2175
- _hoisted_4$f,
2176
- createElementVNode("div", _hoisted_5$c, [
2177
- createElementVNode(
2178
- "div",
2179
- {
2180
- class: normalizeClass(["item", focused.value === "from" ? "current" : ""]),
2181
- onClick: _cache[0] || (_cache[0] = ($event) => switchDateInput("from"))
2182
- },
2183
- toDisplayString(formatDate(result.from)),
2184
- 3
2185
- /* TEXT, CLASS */
2186
- ),
2187
- _hoisted_6$8,
2188
- createElementVNode(
2189
- "div",
2190
- {
2191
- class: normalizeClass(["item", focused.value === "to" ? "current" : ""]),
2192
- onClick: _cache[1] || (_cache[1] = ($event) => switchDateInput("to"))
2193
- },
2194
- toDisplayString(formatDate(result.to)),
2195
- 3
2196
- /* TEXT, CLASS */
2197
- )
2198
- ])
2199
- ]),
2200
- createElementVNode("div", { class: "buttons spa-between" }, [
2201
- createElementVNode("div", {
2202
- class: "btn",
2203
- onClick: reset
2204
- }, "\u91CD\u7F6E"),
2205
- createElementVNode("div", {
2206
- class: "btn confirm",
2207
- onClick: onOkClick
2208
- }, "\u786E\u5B9A")
2209
- ]),
2210
- _hoisted_7$6
2219
+ return openBlock(), createElementBlock("div", _hoisted_1$s, [
2220
+ _hoisted_2$o,
2221
+ createElementVNode("div", _hoisted_3$j, [
2222
+ _hoisted_4$f,
2223
+ createElementVNode("div", _hoisted_5$c, [
2224
+ createElementVNode(
2225
+ "div",
2226
+ {
2227
+ class: normalizeClass(["item", focused.value === "from" ? "current" : ""]),
2228
+ onClick: _cache[0] || (_cache[0] = ($event) => switchDateInput("from"))
2229
+ },
2230
+ toDisplayString(formatDate(result.from)),
2231
+ 3
2232
+ /* TEXT, CLASS */
2233
+ ),
2234
+ _hoisted_6$8,
2235
+ createElementVNode(
2236
+ "div",
2237
+ {
2238
+ class: normalizeClass(["item", focused.value === "to" ? "current" : ""]),
2239
+ onClick: _cache[1] || (_cache[1] = ($event) => switchDateInput("to"))
2240
+ },
2241
+ toDisplayString(formatDate(result.to)),
2242
+ 3
2243
+ /* TEXT, CLASS */
2244
+ )
2245
+ ])
2246
+ ]),
2247
+ createElementVNode("div", { class: "buttons spa-between" }, [
2248
+ createElementVNode("div", {
2249
+ class: "btn",
2250
+ onClick: reset
2251
+ }, "\u91CD\u7F6E"),
2252
+ createElementVNode("div", {
2253
+ class: "btn confirm",
2254
+ onClick: onOkClick
2255
+ }, "\u786E\u5B9A")
2256
+ ]),
2257
+ _hoisted_7$6,
2258
+ createVNode(_component_nut_popup, {
2259
+ visible: datePickerOpen.value,
2260
+ "onUpdate:visible": _cache[4] || (_cache[4] = ($event) => datePickerOpen.value = $event),
2261
+ position: "bottom"
2262
+ }, {
2263
+ default: withCtx(() => [
2264
+ createVNode(_component_nut_date_picker, {
2265
+ modelValue: focusedDate.value,
2266
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => focusedDate.value = $event),
2267
+ "min-date": minDate.value,
2268
+ "max-date": maxDate.value,
2269
+ "is-show-chinese": false,
2270
+ "three-dimensional": false,
2271
+ onCancel: _cache[3] || (_cache[3] = ($event) => datePickerOpen.value = false),
2272
+ onConfirm: onDatePickerComplete
2273
+ }, null, 8, ["modelValue", "min-date", "max-date"])
2211
2274
  ]),
2212
- createVNode(_component_nut_popup, {
2213
- visible: datePickerOpen.value,
2214
- "onUpdate:visible": _cache[4] || (_cache[4] = ($event) => datePickerOpen.value = $event),
2215
- position: "bottom"
2216
- }, {
2217
- default: withCtx(() => [
2218
- createVNode(_component_nut_date_picker, {
2219
- modelValue: focusedDate.value,
2220
- "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => focusedDate.value = $event),
2221
- "min-date": minDate.value,
2222
- "max-date": maxDate.value,
2223
- "is-show-chinese": false,
2224
- "three-dimensional": false,
2225
- onCancel: _cache[3] || (_cache[3] = ($event) => datePickerOpen.value = false),
2226
- onConfirm: onDatePickerComplete
2227
- }, null, 8, ["modelValue", "min-date", "max-date"])
2228
- ]),
2229
- _: 1
2230
- /* STABLE */
2231
- }, 8, ["visible"])
2232
- ],
2233
- 64
2234
- /* STABLE_FRAGMENT */
2235
- );
2275
+ _: 1
2276
+ /* STABLE */
2277
+ }, 8, ["visible"])
2278
+ ]);
2236
2279
  };
2237
2280
  }
2238
2281
  });
@@ -3071,7 +3114,7 @@ var script$o = /* @__PURE__ */ defineComponent({
3071
3114
 
3072
3115
  script$o.__file = "src/balance/components/BalanceReminder.vue";
3073
3116
 
3074
- const _hoisted_1$m = { class: "text number" };
3117
+ const _hoisted_1$m = { class: "text" };
3075
3118
  const _hoisted_2$i = /* @__PURE__ */ createElementVNode(
3076
3119
  "img",
3077
3120
  {
@@ -3085,47 +3128,55 @@ const _hoisted_2$i = /* @__PURE__ */ createElementVNode(
3085
3128
  );
3086
3129
  var script$n = /* @__PURE__ */ defineComponent({
3087
3130
  __name: "DateRange",
3131
+ props: {
3132
+ "modelValue": {
3133
+ type: Object,
3134
+ required: false,
3135
+ default: {
3136
+ from: dayjs().add(-1, "M").format("YYYY-MM-DD"),
3137
+ to: dayjs().format("YYYY-MM-DD")
3138
+ }
3139
+ },
3140
+ "modelModifiers": {}
3141
+ },
3142
+ emits: ["update:modelValue"],
3088
3143
  setup(__props) {
3089
3144
  const $n = useNutshell();
3090
- const filtering = reactive({
3091
- from: dayjs().add(-3, "M").format("YYYY-MM-DD"),
3092
- to: dayjs().format("YYYY-MM-DD")
3093
- });
3094
- const openDateFilter = () => {
3145
+ const model = useModel(__props, "modelValue");
3146
+ const openDateRangePicker = () => {
3095
3147
  $n.sheet({
3096
3148
  component: script$t,
3097
3149
  props: {
3098
- from: "2024-08-01",
3099
- to: "2024-08-31"
3150
+ from: model.value.from,
3151
+ to: model.value.to
3152
+ },
3153
+ onComplete(result) {
3154
+ console.log("===openDateFilter complete", result);
3155
+ model.value = {
3156
+ from: result.from,
3157
+ to: result.to
3158
+ };
3100
3159
  }
3101
3160
  });
3102
3161
  };
3103
3162
  const dateRangeDisplay = computed(() => {
3104
- let startTime = (filtering.from || "").replace(/-/g, ".").substring(2);
3105
- let endTime = (filtering.to || "").replace(/-/g, ".").substring(2);
3106
- return startTime + " - " + endTime;
3163
+ let startTime = (model.value.from || "").replace(/-/g, ".").substring(2);
3164
+ let endTime = (model.value.to || "").replace(/-/g, ".").substring(2);
3165
+ return startTime + "-" + endTime;
3107
3166
  });
3108
3167
  return (_ctx, _cache) => {
3109
- return withDirectives((openBlock(), createElementBlock(
3110
- "div",
3111
- {
3112
- class: "date-range",
3113
- onClick: openDateFilter
3114
- },
3115
- [
3116
- createElementVNode(
3117
- "div",
3118
- _hoisted_1$m,
3119
- toDisplayString(dateRangeDisplay.value),
3120
- 1
3121
- /* TEXT */
3122
- ),
3123
- _hoisted_2$i
3124
- ],
3125
- 512
3126
- /* NEED_PATCH */
3127
- )), [
3128
- [vShow, filtering.to]
3168
+ return openBlock(), createElementBlock("div", {
3169
+ class: "date-range",
3170
+ onClick: openDateRangePicker
3171
+ }, [
3172
+ createElementVNode(
3173
+ "div",
3174
+ _hoisted_1$m,
3175
+ toDisplayString(dateRangeDisplay.value),
3176
+ 1
3177
+ /* TEXT */
3178
+ ),
3179
+ _hoisted_2$i
3129
3180
  ]);
3130
3181
  };
3131
3182
  }
@@ -3133,10 +3184,10 @@ var script$n = /* @__PURE__ */ defineComponent({
3133
3184
 
3134
3185
  script$n.__file = "src/balance/components/DateRange.vue";
3135
3186
 
3136
- const _hoisted_1$l = { class: "consumption-filter" };
3187
+ const _hoisted_1$l = { class: "list-filter-picker" };
3137
3188
  const _hoisted_2$h = /* @__PURE__ */ createElementVNode(
3138
3189
  "div",
3139
- { class: "consumption-filter-title" },
3190
+ { class: "list-filter-picker-title" },
3140
3191
  [
3141
3192
  /* @__PURE__ */ createElementVNode("h3", null, "\u9009\u62E9\u7B5B\u9009\u9879")
3142
3193
  ],
@@ -3157,51 +3208,45 @@ const _hoisted_7$4 = /* @__PURE__ */ createElementVNode(
3157
3208
  var script$m = /* @__PURE__ */ defineComponent({
3158
3209
  __name: "ListFilterPicker",
3159
3210
  props: {
3160
- modelValue: { type: null, required: true, default: () => ["\u5168\u90E8", "\u5168\u90E8", "\u5168\u90E8", ""] }
3211
+ modelValue: { type: Object, required: true }
3161
3212
  },
3162
3213
  emits: ["complete"],
3163
3214
  setup(__props, { emit: __emit }) {
3164
- const $http = useHttp$3();
3215
+ useHttp$3();
3165
3216
  const props = __props;
3166
3217
  const emit = __emit;
3167
- const result = reactive(props.modelValue);
3218
+ const result = ref(props.modelValue);
3168
3219
  const filterSections = ref([
3169
3220
  {
3170
- title: "\u7C7B\u578B",
3171
- data: consumptionPositions.map((s) => ({ code: s, name: s }))
3172
- },
3173
- {
3174
- title: "\u6536\u5165/\u652F\u51FA",
3175
- data: consumptionDirections.map((s) => ({ code: s, name: s }))
3176
- },
3177
- {
3178
- title: "\u660E\u7EC6\u7C7B\u578B",
3179
- data: consumptionTypes.map((s) => ({ code: s, name: s }))
3180
- },
3181
- {
3182
- title: "\u6743\u76CA\u7C7B\u76EE",
3183
- data: []
3221
+ label: "\u660E\u7EC6\u7C7B\u578B",
3222
+ name: "type",
3223
+ data: [
3224
+ {
3225
+ label: "\u5168\u90E8",
3226
+ value: ""
3227
+ },
3228
+ {
3229
+ label: "\u63D0\u73B0",
3230
+ value: "withdrawal"
3231
+ },
3232
+ {
3233
+ label: "\u6536\u76CA",
3234
+ value: "income"
3235
+ },
3236
+ {
3237
+ label: "\u5151\u6362",
3238
+ value: "exchange"
3239
+ }
3240
+ ]
3184
3241
  }
3185
3242
  ]);
3186
- const getItemClass = (index, value) => result[index] === value ? ["current"] : [""];
3243
+ const getItemClass = (name, value) => result.value[name]?.includes(value) ? ["current"] : [""];
3187
3244
  const onFilterSectionClick = (index, value) => {
3188
- result[index] = value;
3245
+ result.value[index] = [value];
3189
3246
  };
3190
3247
  const reset = () => {
3191
- result[0] = "\u5168\u90E8";
3192
- result[1] = "\u5168\u90E8";
3193
- result[2] = "\u5168\u90E8";
3194
- result[3] = "";
3248
+ result.value = {};
3195
3249
  };
3196
- const \u8BF7\u6C42\u6743\u76CA\u7C7B\u76EE = () => {
3197
- $http.get(endpoints$1.\u83B7\u53D6\u6743\u76CA\u7C7B\u76EE).then((data) => {
3198
- filterSections.value[3].data = [
3199
- { code: "", name: "\u5168\u90E8" },
3200
- ...data
3201
- ];
3202
- });
3203
- };
3204
- \u8BF7\u6C42\u6743\u76CA\u7C7B\u76EE();
3205
3250
  const onOkClick = () => {
3206
3251
  emit("complete", result);
3207
3252
  };
@@ -3220,7 +3265,7 @@ var script$m = /* @__PURE__ */ defineComponent({
3220
3265
  createElementVNode(
3221
3266
  "div",
3222
3267
  _hoisted_4$a,
3223
- toDisplayString(item.title),
3268
+ toDisplayString(item.label),
3224
3269
  1
3225
3270
  /* TEXT */
3226
3271
  ),
@@ -3230,10 +3275,10 @@ var script$m = /* @__PURE__ */ defineComponent({
3230
3275
  null,
3231
3276
  renderList(item.data, (it, i) => {
3232
3277
  return openBlock(), createElementBlock("div", {
3233
- onClick: () => onFilterSectionClick(index, it.code),
3234
- class: normalizeClass([getItemClass(index, it.code), "info-item"]),
3278
+ onClick: () => onFilterSectionClick(item.name, it.value),
3279
+ class: normalizeClass([getItemClass(item.name, it.value), "info-item"]),
3235
3280
  key: i
3236
- }, toDisplayString(typeof it === "string" ? it : it.name), 11, _hoisted_6$6);
3281
+ }, toDisplayString(typeof it === "string" ? it : it.label), 11, _hoisted_6$6);
3237
3282
  }),
3238
3283
  128
3239
3284
  /* KEYED_FRAGMENT */
@@ -3289,11 +3334,32 @@ const _hoisted_3$c = [
3289
3334
  ];
3290
3335
  var script$l = /* @__PURE__ */ defineComponent({
3291
3336
  __name: "ListFilter",
3292
- setup(__props) {
3337
+ props: {
3338
+ "modelValue": {
3339
+ type: Object,
3340
+ default: {
3341
+ type: ""
3342
+ },
3343
+ required: false
3344
+ },
3345
+ "modelModifiers": {}
3346
+ },
3347
+ emits: /* @__PURE__ */ mergeModels(["update:modelValue", "change"], ["update:modelValue"]),
3348
+ setup(__props, { emit: __emit }) {
3293
3349
  const $n = useNutshell();
3350
+ const model = useModel(__props, "modelValue");
3351
+ const emit = __emit;
3294
3352
  const openPicker = () => {
3295
3353
  $n.sheet({
3296
- component: script$m
3354
+ component: script$m,
3355
+ props: {
3356
+ modelValue: model,
3357
+ onComplete: (result) => {
3358
+ emit("update:modelValue", {
3359
+ type: result[0]
3360
+ });
3361
+ }
3362
+ }
3297
3363
  });
3298
3364
  };
3299
3365
  return (_ctx, _cache) => {
@@ -4923,25 +4989,16 @@ const _hoisted_2$8 = { class: "user-entry-head" };
4923
4989
  const _hoisted_3$5 = ["src"];
4924
4990
  const _hoisted_4$5 = { class: "user-entry-bd" };
4925
4991
  const _hoisted_5$5 = /* @__PURE__ */ createElementVNode(
4926
- "img",
4927
- {
4928
- class: "user-entry-bd-bigtxt-icon",
4929
- mode: "aspectFit",
4930
- src: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA0MCA0MSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggb3BhY2l0eT0iMC4wMSIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0wIDQwLjM1MTZINDBWMC4zNTE1NjJIMFY0MC4zNTE2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNCA4LjM1MTU2TDI2IDIwLjM1MTZMMTQgMzIuMzUxNiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC4wMSIvPgo8cGF0aCBkPSJNMTQgOC4zNTE1NkwyNiAyMC4zNTE2TDE0IDMyLjM1MTYiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+Cg==",
4931
- alt: ""
4932
- },
4933
- null,
4992
+ "span",
4993
+ { class: "user-entry-bd-arrow" },
4994
+ ">",
4934
4995
  -1
4935
4996
  /* HOISTED */
4936
4997
  );
4937
4998
  const _hoisted_6$3 = /* @__PURE__ */ createElementVNode(
4938
- "img",
4939
- {
4940
- style: { "width": "14px", "height": "14px", "margin-left": "2px" },
4941
- src: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjgiIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTExLjA4MzUgN0wxOC4wODM1IDE0TDExLjA4MzUgMjEiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS43NSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPgo=",
4942
- alt: ""
4943
- },
4944
- null,
4999
+ "span",
5000
+ { class: "user-entry-bd-arrow" },
5001
+ ">",
4945
5002
  -1
4946
5003
  /* HOISTED */
4947
5004
  );
@@ -7655,4 +7712,4 @@ const AppKit = {
7655
7712
  }
7656
7713
  };
7657
7714
 
7658
- export { script$p as AccountView, script$H as AmountPicker, script$E as AppDrawer, script$D as AppVerify, script$v as BalanceCard, script$o as BalanceReminder, script$n as DateRange, script$B as DeviceVersion, script$l as ListFilter, script$1 as LoginSetting, script$e as NoticeBanner, script$d as NoticeEntry, script$b as NoticeList, script$A as OcrIcon, script$F as PageHeader, script$y as RechargeResult, script$z as RechargeView, script$g as SelfRegistration, script$w as TradeView, script$G as UserAgreement, script$7 as UserBinding, script$6 as UserBindingSuccess, script$a as UserEntry, script$3 as UserFeedback, script$2 as UserFeedbackEntry, script$4 as UserHeadCrop, script$8 as UserInfo, script as UserResourceEmpty, components, createHttp, AppKit as default, requestPayment$2 as requestPayment, services$1 as services, useAppKit, useCountdown, useEncode, useSafeArea, useTabbar, useUpload, useValidator };
7715
+ export { script$p as AccountView, script$H as AmountPicker, script$E as AppDrawer, script$D as AppVerify, script$v as BalanceCard, script$o as BalanceReminder, script$n as DateRange, script$B as DeviceVersion, script$l as ListFilter, script$1 as LoginSetting, script$e as NoticeBanner, script$d as NoticeEntry, script$b as NoticeList, script$A as OcrIcon, script$F as PageHeader, script$y as RechargeResult, script$z as RechargeView, script$g as SelfRegistration, script$w as TradeView, script$G as UserAgreement, script$7 as UserBinding, script$6 as UserBindingSuccess, script$a as UserEntry, script$3 as UserFeedback, script$2 as UserFeedbackEntry, script$4 as UserHeadCrop, script$8 as UserInfo, script as UserResourceEmpty, components, createHttp, AppKit as default, defaultCryptoConfig, requestPayment$2 as requestPayment, services$1 as services, useAppKit, useCountdown, useCrypto, useEncode, useSafeArea, useTabbar, useUpload, useValidator };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxda/appkit",
3
- "version": "4.0.12",
3
+ "version": "4.0.16",
4
4
  "description": "小程序应用开发包",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.ts",
@@ -22,18 +22,18 @@
22
22
  <div class="btn confirm" @click="onOkClick">确定</div>
23
23
  </div>
24
24
  <div class="bottom"></div>
25
+ <nut-popup v-model:visible="datePickerOpen" position="bottom">
26
+ <nut-date-picker
27
+ v-model="focusedDate"
28
+ :min-date="minDate"
29
+ :max-date="maxDate"
30
+ :is-show-chinese="false"
31
+ :three-dimensional="false"
32
+ @cancel="datePickerOpen = false"
33
+ @confirm="onDatePickerComplete"
34
+ ></nut-date-picker>
35
+ </nut-popup>
25
36
  </div>
26
- <nut-popup v-model:visible="datePickerOpen" position="bottom">
27
- <nut-date-picker
28
- v-model="focusedDate"
29
- :min-date="minDate"
30
- :max-date="maxDate"
31
- :is-show-chinese="false"
32
- :three-dimensional="false"
33
- @cancel="datePickerOpen = false"
34
- @confirm="onDatePickerComplete"
35
- ></nut-date-picker>
36
- </nut-popup>
37
37
  </template>
38
38
 
39
39
  <script lang="ts" setup>
@@ -126,6 +126,7 @@ function switchDateInput(shift: string) {
126
126
  display: flex;
127
127
  flex-direction: column;
128
128
  width: 100%;
129
+ position: relative;
129
130
  .date-filter-header {
130
131
  text-align: center;
131
132
  height: 44px;
@@ -1,6 +1,6 @@
1
1
  <template>
2
- <div class="date-range" @click="openDateFilter" v-show="filtering.to">
3
- <div class="text number">{{ dateRangeDisplay }}</div>
2
+ <div class="date-range" @click="openDateRangePicker">
3
+ <div class="text">{{ dateRangeDisplay }}</div>
4
4
  <img
5
5
  style="margin-top: -2px"
6
6
  class="time-icon"
@@ -10,32 +10,48 @@
10
10
  </template>
11
11
 
12
12
  <script lang="ts" setup>
13
- import { computed, reactive } from 'vue'
13
+ import { computed, PropType, reactive } from 'vue'
14
14
  import { useNutshell } from '@uxda/nutshell/taro'
15
15
  import DateFilter from './DateFilter.vue'
16
16
  import dayjs from 'dayjs'
17
17
 
18
18
  const $n = useNutshell()
19
19
 
20
- const filtering = reactive({
21
- from: dayjs().add(-3, 'M').format('YYYY-MM-DD'),
22
- to: dayjs().format('YYYY-MM-DD'),
20
+ export type DateRangeModel = {
21
+ from: string,
22
+ to: string
23
+ }
24
+
25
+ const model = defineModel({
26
+ type: Object as PropType<DateRangeModel>,
27
+ required: false,
28
+ default: {
29
+ from: dayjs().add(-1, 'M').format('YYYY-MM-DD'),
30
+ to: dayjs().format('YYYY-MM-DD')
31
+ }
23
32
  })
24
33
 
25
- const openDateFilter = () => {
34
+ const openDateRangePicker = () => {
26
35
  $n.sheet({
27
36
  component: DateFilter,
28
37
  props: {
29
- from: '2024-08-01',
30
- to: '2024-08-31',
38
+ from: model.value.from,
39
+ to: model.value.to,
40
+ },
41
+ onComplete (result: any) {
42
+ console.log('===openDateFilter complete', result)
43
+ model.value = {
44
+ from: result.from,
45
+ to: result.to
46
+ }
31
47
  }
32
48
  })
33
49
  }
34
50
 
35
51
  const dateRangeDisplay = computed(() => {
36
- let startTime = (filtering.from || '').replace(/-/g, '.').substring(2)
37
- let endTime = (filtering.to || '').replace(/-/g, '.').substring(2)
38
- return startTime + ' - ' + endTime
52
+ let startTime = (model.value.from || '').replace(/-/g, '.').substring(2)
53
+ let endTime = (model.value.to || '').replace(/-/g, '.').substring(2)
54
+ return startTime + '-' + endTime
39
55
  })
40
56
 
41
57
  </script>
@@ -9,16 +9,40 @@
9
9
  </template>
10
10
 
11
11
  <script lang="ts" setup>
12
- import { computed, reactive } from 'vue'
12
+ import { computed, PropType, reactive } from 'vue'
13
13
  import { useNutshell } from '@uxda/nutshell/taro'
14
14
  import ListFilterPicker from './ListFilterPicker.vue'
15
15
 
16
16
  const $n = useNutshell()
17
17
 
18
+ export type ListFilterValue = {
19
+ type: string,
20
+ }
21
+
22
+ const model = defineModel({
23
+ type: Object as PropType<ListFilterValue>,
24
+ default: {
25
+ type: ''
26
+ },
27
+ required: false,
28
+ })
29
+
30
+ const emit = defineEmits<{
31
+ (e: 'update:modelValue', v: ListFilterValue): void,
32
+ (e: 'change'): void,
33
+ }>()
34
+
18
35
  const openPicker = () => {
19
36
  $n.sheet({
20
37
  component: ListFilterPicker,
21
-
38
+ props: {
39
+ modelValue: model,
40
+ onComplete: (result) => {
41
+ emit('update:modelValue', {
42
+ type: result[0]
43
+ })
44
+ }
45
+ }
22
46
  })
23
47
  }
24
48
  </script>
@@ -1,19 +1,19 @@
1
1
  <template>
2
- <div class="consumption-filter">
3
- <div class="consumption-filter-title">
2
+ <div class="list-filter-picker">
3
+ <div class="list-filter-picker-title">
4
4
  <h3>选择筛选项</h3>
5
5
  </div>
6
6
  <div class="consumption-filter-content">
7
7
  <template v-for="(item, index) in filterSections" :key="index">
8
- <div class="title">{{ item.title }}</div>
8
+ <div class="title">{{ item.label }}</div>
9
9
  <div class="info">
10
10
  <div
11
11
  v-for="(it, i) in item.data"
12
- @click="() => onFilterSectionClick(index, it.code)"
13
- :class="getItemClass(index, it.code)"
12
+ @click="() => onFilterSectionClick(item.name, it.value)"
13
+ :class="getItemClass(item.name, it.value)"
14
14
  class="info-item"
15
15
  :key="i">
16
- {{ typeof it === 'string' ? it : it.name }}
16
+ {{ typeof it === 'string' ? it : it.label }}
17
17
  </div>
18
18
  </div>
19
19
  </template>
@@ -33,21 +33,22 @@ import { UniData, UniDataItem } from '@uxda/nutshell/taro'
33
33
 
34
34
  const $http = useHttp()
35
35
 
36
- interface ConsumptionFilterProps {
37
- modelValue: ConsumptionFilterModelValue
36
+ type ListFilterPickerModel = Record<string, string[]>
37
+
38
+ interface ListFilterPickerProps {
39
+ modelValue: ListFilterPickerModel
38
40
  }
39
41
 
40
- const props = withDefaults(
41
- defineProps<ConsumptionFilterProps>(), {
42
- modelValue: () => ['全部', '全部', '全部', '']
43
- }
44
- )
42
+ const props =
43
+ defineProps<ListFilterPickerProps>()
44
+
45
45
  const emit = defineEmits(['complete'])
46
46
 
47
- const result = reactive<ConsumptionFilterModelValue>(props.modelValue)
47
+ const result = ref<ListFilterPickerModel>(props.modelValue)
48
48
 
49
49
  type FilterSecion = {
50
- title: string,
50
+ label: string,
51
+ name: string,
51
52
  data: UniDataItem[]
52
53
  }
53
54
 
@@ -56,54 +57,45 @@ type FilterSecion = {
56
57
  */
57
58
  const filterSections = ref<FilterSecion[]>([
58
59
  {
59
- title: '类型',
60
- data: consumptionPositions.map(s => ({code: s, name: s})),
61
- },
62
- {
63
- title: '收入/支出',
64
- data: consumptionDirections.map(s => ({code: s, name: s})),
65
- },
66
- {
67
- title: '明细类型',
68
- data: consumptionTypes.map(s => ({code: s, name: s})),
60
+ label: '明细类型',
61
+ name: 'type',
62
+ data: [
63
+ {
64
+ label: '全部',
65
+ value: ''
66
+ },
67
+ {
68
+ label: '提现',
69
+ value: 'withdrawal'
70
+ },
71
+ {
72
+ label: '收益',
73
+ value: 'income'
74
+ },
75
+ {
76
+ label: '兑换',
77
+ value: 'exchange'
78
+ }
79
+ ]
69
80
  },
70
- {
71
- title: '权益类目',
72
- data: []
73
- }
74
81
  ])
75
82
 
76
- const getItemClass = (index: number, value) => result[index] === value ? ['current'] : ['']
83
+ const getItemClass = (name: string, value: string) => result.value[name]?.includes(value) ? ['current'] : ['']
77
84
 
78
- const onFilterSectionClick = (index: number, value: MixteValues) => {
79
- result[index] = value
85
+ const onFilterSectionClick = (index: string, value: string) => {
86
+ result.value[index] = [value]
80
87
  }
81
88
 
82
89
  const reset = () => {
83
- result[0] = '全部'
84
- result[1] = '全部'
85
- result[2] = '全部'
86
- result[3] = ''
90
+ result.value = {}
87
91
  }
88
92
 
89
- const 请求权益类目 = () => {
90
- $http.get<权益类目[]>(endpoints.获取权益类目).then(data => {
91
- filterSections.value[3].data = [
92
- { code: '', name: '全部' },
93
- ...data
94
- ]
95
- })
96
- }
97
-
98
- 请求权益类目()
99
-
100
93
  const onOkClick = () => {
101
94
  emit('complete', result)
102
95
  }
103
96
  </script>
104
97
  <style lang="scss">
105
- .consumption-filter {
106
- height: 100%;
98
+ .list-filter-picker {
107
99
  display: flex;
108
100
  flex-direction: column;
109
101
  width: 100%;
@@ -4,20 +4,33 @@
4
4
  <p class="caption">{{ message || '短信将发送至账号绑定手机号' }}</p>
5
5
  <p class="number">{{ phone }}</p>
6
6
  <ns-form v-model="formData">
7
- <ns-input name="code" placeholder="请输入验证码" variant="solid" :rules="['required', {
7
+ <ns-input
8
+ name="code"
9
+ v-model="formData.code"
10
+ placeholder="请输入验证码"
11
+ variant="solid"
12
+ :rules="['required', {
8
13
  name: 'function',
9
14
  message: '输入错误, 请重新输入',
10
- method: (value: string) => value.length === 4,
11
- }]">
15
+ method: (value: string) => value.length === 6,
16
+ }]"
17
+ >
12
18
  <template #append>
13
- <ns-button v-if="!sent" size="xs" variant="plain" color="primary" @click="send" label="获取验证码" />
19
+ <ns-button
20
+ v-if="!sent"
21
+ size="xs"
22
+ variant="plain"
23
+ color="primary"
24
+ @click="send"
25
+ label="获取验证码"
26
+ />
14
27
  <div class="caption" v-if="sent">{{ countdown }} 秒收重新发送</div>
15
28
  </template>
16
29
  </ns-input>
17
30
  </ns-form>
18
31
  <div class="row buttons">
19
- <ns-button round>取消</ns-button>
20
- <ns-button round gradient="#FFEBC1,#FFD7A7,#FFB875/90">确认</ns-button>
32
+ <ns-button round @click="emits('cancel')">取消</ns-button>
33
+ <ns-button round gradient="#FFEBC1,#FFD7A7,#FFB875/90" @click="onOk">确认</ns-button>
21
34
  </div>
22
35
  </div>
23
36
  </template>
@@ -27,27 +40,29 @@ import { NsForm, NsInput, NsButton } from '@uxda/nutshell/taro'
27
40
  import { reactive, ref } from 'vue'
28
41
 
29
42
  export interface AppVerifyProps {
30
- phone: string,
31
- title?: string,
32
- message?: string,
43
+ phone: string
44
+ title?: string
45
+ message?: string
46
+ onSend?: Function
33
47
  }
34
48
 
35
- const emit = defineEmits<{
36
- (event: 'update:modelValue', value: boolean): void
37
- }>()
49
+ const emits = defineEmits(['complete', 'cancel'])
38
50
 
39
51
  const sent = ref(false),
40
52
  countdown = ref(60)
41
53
 
42
54
  let formData = reactive({
43
- code: ''
55
+ code: '',
44
56
  })
45
57
 
46
58
  const send = () => {
47
59
  sent.value = true
60
+
61
+ props.onSend && props.onSend()
62
+
48
63
  countdown.value = 60
49
64
  let timer = setInterval(() => {
50
- countdown.value --
65
+ countdown.value--
51
66
  if (countdown.value <= 0) {
52
67
  clearInterval(timer)
53
68
  sent.value = false
@@ -55,12 +70,11 @@ const send = () => {
55
70
  }, 1000)
56
71
  }
57
72
 
58
- const onVisibleChange = (value: boolean) => {
59
- emit('update:modelValue', value)
73
+ const onOk = () => {
74
+ emits('complete', { code: formData.code })
60
75
  }
61
76
 
62
- defineProps<AppVerifyProps>()
63
-
77
+ const props = defineProps<AppVerifyProps>()
64
78
  </script>
65
79
 
66
80
  <style lang="scss">
@@ -81,4 +95,4 @@ defineProps<AppVerifyProps>()
81
95
  }
82
96
  }
83
97
  }
84
- </style>
98
+ </style>
@@ -4,3 +4,4 @@ export * from './useCountdown'
4
4
  export * from './useValidator'
5
5
  export * from './useEncode'
6
6
  export * from './useUpload'
7
+ export * from './useCrypto'
@@ -0,0 +1,76 @@
1
+ // 解析脱敏姓名、手机号码等
2
+
3
+ export type CryptoConfig = {
4
+ maskField: string,
5
+ secretField: string,
6
+ }
7
+
8
+ export const defaultCryptoConfig: CryptoConfig = {
9
+ maskField: 'mask',
10
+ secretField: 'secretKey'
11
+ }
12
+
13
+ export type DecodeResult<T extends string> = {
14
+ [key in T | `${T}Secret`]: string
15
+ }
16
+
17
+ export type DefaultDecodeResult = DecodeResult<'masked'>
18
+
19
+ export type DecodeFunction = (encoded: string, key: string) => DecodeResult<`${key}`>
20
+
21
+ /**
22
+ * 解析以及解密脱敏数据
23
+ * @param config
24
+ * @returns
25
+ */
26
+ export function useCrypto (config?: CryptoConfig) {
27
+
28
+ const conf = config || defaultCryptoConfig
29
+
30
+ const parse: DecodeFunction = (data: string, key?: string) => {
31
+ let k = key || 'masked'
32
+ let result: Record<string, any> = {}
33
+ try {
34
+ result = JSON.parse(data)
35
+ result = {
36
+ [k]: result.mask,
37
+ // 字段后加$表示用于解密的 secret
38
+ [`${k}$`]: result.secretKey
39
+ }
40
+ } catch (e) {}
41
+ return result
42
+ }
43
+
44
+ /**
45
+ * 批量解析数组内的数据
46
+ * @param list
47
+ * @param field
48
+ * @returns
49
+ */
50
+ const resolve = (list: any[], field?: string | string[]) => {
51
+ const [first] = list,
52
+ f = field
53
+ ? Array.isArray(field) ? field : [field]
54
+ // 自动探测需要解密的字段
55
+ // '{"secretKey":"","mask":""}' 形式
56
+ : Object.entries(first)
57
+ .filter(([_, v]) => /^\{.*\}$/.test(v as string))
58
+ .map(([k]) => k)
59
+ return list
60
+ .map(item => {
61
+ let result = { ...item }
62
+ f.forEach(r => {
63
+ result = {
64
+ ...result,
65
+ ...parse(item[r], r)
66
+ }
67
+ })
68
+ return result
69
+ })
70
+ }
71
+
72
+ return {
73
+ parse,
74
+ resolve,
75
+ }
76
+ }
@@ -21,21 +21,12 @@
21
21
  <div class="user-entry-bd">
22
22
  <div v-if="!mobile" class="user-entry-bd-bigtxt" @click="toLogin">
23
23
  请登录
24
- <img
25
- class="user-entry-bd-bigtxt-icon"
26
- mode="aspectFit"
27
- src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA0MCA0MSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggb3BhY2l0eT0iMC4wMSIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0wIDQwLjM1MTZINDBWMC4zNTE1NjJIMFY0MC4zNTE2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNCA4LjM1MTU2TDI2IDIwLjM1MTZMMTQgMzIuMzUxNiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC4wMSIvPgo8cGF0aCBkPSJNMTQgOC4zNTE1NkwyNiAyMC4zNTE2TDE0IDMyLjM1MTYiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+Cg=="
28
- alt=""
29
- />
24
+ <span class="user-entry-bd-arrow">></span>
30
25
  </div>
31
26
  <template v-else>
32
27
  <div @click="toUser" class="user-entry-bd-txt">
33
28
  {{ name }}
34
- <img
35
- style="width: 14px; height: 14px; margin-left: 2px"
36
- src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjgiIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTExLjA4MzUgN0wxOC4wODM1IDE0TDExLjA4MzUgMjEiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS43NSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPgo="
37
- alt=""
38
- />
29
+ <span class="user-entry-bd-arrow">></span>
39
30
  </div>
40
31
  <div @click="toUser" class="user-entry-bd-smalltxt">{{ encodePhone(mobile) }}</div>
41
32
  </template>
@@ -137,6 +128,10 @@ const emits = defineEmits(['jump', 'login'])
137
128
  font-size: 15px;
138
129
  line-height: 21px;
139
130
  }
131
+ &-arrow {
132
+ font-size: 12px;
133
+ margin-left: 8px;
134
+ }
140
135
  }
141
136
  }
142
137
  </style>