@peng_kai/kit 0.2.0-beta.22 → 0.2.0-beta.24

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.
@@ -1,121 +1,121 @@
1
- <script lang="ts">
2
- import { computed } from 'vue';
3
- import bigNumber from 'bignumber.js';
4
- import isNil from 'lodash-es/isNil';
5
-
6
- export const config = {
7
- aboveColor: '#52c41a',
8
- belowColor: '#ff4d4f',
9
- };
10
-
11
- /**
12
- * 当 symbol 为以下值时,使用预设的 Logo
13
- */
14
- const presetSymbols: Record<string, string> = {
15
- USDT: 'https://api.iconify.design/cryptocurrency-color:usdt.svg',
16
- TRX: 'https://api.iconify.design/cryptocurrency-color:trx.svg',
17
- USDC: 'https://api.iconify.design/cryptocurrency-color:usdc.svg',
18
- ETH: 'https://api.iconify.design/cryptocurrency-color:eth.svg',
19
- BNB: 'https://api.iconify.design/cryptocurrency-color:bnb.svg',
20
- BUSD: 'https://assets.coingecko.com/coins/images/9576/large/BUSD.png',
21
- MATIC: 'https://api.iconify.design/cryptocurrency-color:matic.svg',
22
- SOL: 'https://api.iconify.design/cryptocurrency-color:sol.svg',
23
- };
24
- </script>
25
-
26
- <script setup lang="ts">
27
- const props = withDefaults(
28
- defineProps<{
29
- /** 金额 */
30
- amount?: string | number
31
- /** 符号Logo, 可以是币种Logo的URL、法定货币符号($) */
32
- symbol?: string
33
- /** 精度 */
34
- precision?: number
35
- /** 单位,如币种名称 */
36
- unit?: string
37
- /** 保留小数的位数 */
38
- fractionDigits?: number
39
- /** 是否填充 0 */
40
- padZero?: boolean
41
- /** 金额是否红/绿显示 */
42
- colorful?: boolean
43
- /** 是否是大约数 */
44
- approx?: boolean
45
- }>(),
46
- {
47
- padZero: false,
48
- fractionDigits: 18,
49
- colorful: false,
50
- },
51
- );
52
-
53
- const amountText = computed(() => {
54
- const _amount = props.amount;
55
-
56
- if (isNil(_amount))
57
- return '-';
58
-
59
- let bn = bigNumber(_amount);
60
- bn = !isNil(props.precision) ? bn.dividedBy(10 ** props.precision) : bn;
61
- let bnt = bn.toFormat(props.fractionDigits);
62
- bnt = props.padZero ? bnt : bnt.replace(/\.?0+$/, '');
63
-
64
- return bnt;
65
- });
66
- const amountColor = computed(() => {
67
- const num = Number.parseFloat(props.amount as string);
68
-
69
- if (!props.colorful || (Number.isNaN(num) ? true : num === 0))
70
- return '';
71
-
72
- return num > 0 ? config.aboveColor : (num < 0 ? config.belowColor : '');
73
- });
74
- const symbol = computed(() => presetSymbols[props.symbol!] ?? props.symbol ?? '');
75
- </script>
76
-
77
- <template>
78
- <div class="amount-wrapper" :style="{ '--amount-color': amountColor }">
79
- <!-- 约等于 -->
80
- <span v-if="props.approx" class="color-$amount-color">≈</span>
81
-
82
- <!-- 符号 -->
83
- <img v-if="symbol.startsWith('http')" class="symbol-logo" :src="symbol">
84
-
85
- <!-- 图片Logo -->
86
- <span v-else class="color-$amount-color">{{ symbol }}</span> <!-- 文本Logo,如法定币种符号(¥、$) -->
87
-
88
- <!-- 金额 -->
89
- <span class="color-$amount-color amount">{{ amountText }}</span>
90
-
91
- <!-- 单位 -->
92
- <span v-if="props.unit" class="unit">{{ props.unit }}</span>
93
- </div>
94
- </template>
95
-
96
- <style lang="scss">
97
- .amount-wrapper {
98
- display: flex;
99
- align-items: center;
100
-
101
- .symbol-logo {
102
- display: block;
103
- width: 1.1em;
104
- height: 1.1em;
105
- margin-right: 0.2em;
106
- }
107
-
108
- .amount {
109
- font-family: 'dinm';
110
- }
111
-
112
- .currency-name {
113
- margin-left: 0.2em;
114
- }
115
-
116
- .unit {
117
- display: inline-block;
118
- margin-left: 0.2em;
119
- }
120
- }
121
- </style>
1
+ <script lang="ts">
2
+ import { computed } from 'vue';
3
+ import bigNumber from 'bignumber.js';
4
+ import isNil from 'lodash-es/isNil';
5
+
6
+ export const config = {
7
+ aboveColor: '#52c41a',
8
+ belowColor: '#ff4d4f',
9
+ };
10
+
11
+ /**
12
+ * 当 symbol 为以下值时,使用预设的 Logo
13
+ */
14
+ const presetSymbols: Record<string, string> = {
15
+ USDT: 'https://api.iconify.design/cryptocurrency-color:usdt.svg',
16
+ TRX: 'https://api.iconify.design/cryptocurrency-color:trx.svg',
17
+ USDC: 'https://api.iconify.design/cryptocurrency-color:usdc.svg',
18
+ ETH: 'https://api.iconify.design/cryptocurrency-color:eth.svg',
19
+ BNB: 'https://api.iconify.design/cryptocurrency-color:bnb.svg',
20
+ BUSD: 'https://assets.coingecko.com/coins/images/9576/large/BUSD.png',
21
+ MATIC: 'https://api.iconify.design/cryptocurrency-color:matic.svg',
22
+ SOL: 'https://api.iconify.design/cryptocurrency-color:sol.svg',
23
+ };
24
+ </script>
25
+
26
+ <script setup lang="ts">
27
+ const props = withDefaults(
28
+ defineProps<{
29
+ /** 金额 */
30
+ amount?: string | number
31
+ /** 符号Logo, 可以是币种Logo的URL、法定货币符号($) */
32
+ symbol?: string
33
+ /** 精度 */
34
+ precision?: number
35
+ /** 单位,如币种名称 */
36
+ unit?: string
37
+ /** 保留小数的位数 */
38
+ fractionDigits?: number
39
+ /** 是否填充 0 */
40
+ padZero?: boolean
41
+ /** 金额是否红/绿显示 */
42
+ colorful?: boolean
43
+ /** 是否是大约数 */
44
+ approx?: boolean
45
+ }>(),
46
+ {
47
+ padZero: false,
48
+ fractionDigits: 18,
49
+ colorful: false,
50
+ },
51
+ );
52
+
53
+ const amountText = computed(() => {
54
+ const _amount = props.amount;
55
+
56
+ if (isNil(_amount))
57
+ return '-';
58
+
59
+ let bn = bigNumber(_amount);
60
+ bn = !isNil(props.precision) ? bn.dividedBy(10 ** props.precision) : bn;
61
+ let bnt = bn.toFormat(props.fractionDigits);
62
+ bnt = props.padZero ? bnt : bnt.replace(/\.?0+$/, '');
63
+
64
+ return bnt;
65
+ });
66
+ const amountColor = computed(() => {
67
+ const num = Number.parseFloat(props.amount as string);
68
+
69
+ if (!props.colorful || (Number.isNaN(num) ? true : num === 0))
70
+ return '';
71
+
72
+ return num > 0 ? config.aboveColor : (num < 0 ? config.belowColor : '');
73
+ });
74
+ const symbol = computed(() => presetSymbols[props.symbol!] ?? props.symbol ?? '');
75
+ </script>
76
+
77
+ <template>
78
+ <div class="amount-wrapper" :style="{ '--amount-color': amountColor }">
79
+ <!-- 约等于 -->
80
+ <span v-if="props.approx" class="color-$amount-color">≈</span>
81
+
82
+ <!-- 符号 -->
83
+ <img v-if="symbol.startsWith('http')" class="symbol-logo" :src="symbol">
84
+
85
+ <!-- 图片Logo -->
86
+ <span v-else class="color-$amount-color">{{ symbol }}</span> <!-- 文本Logo,如法定币种符号(¥、$) -->
87
+
88
+ <!-- 金额 -->
89
+ <span class="color-$amount-color amount">{{ amountText }}</span>
90
+
91
+ <!-- 单位 -->
92
+ <span v-if="props.unit" class="unit">{{ props.unit }}</span>
93
+ </div>
94
+ </template>
95
+
96
+ <style lang="scss">
97
+ .amount-wrapper {
98
+ display: flex;
99
+ align-items: center;
100
+
101
+ .symbol-logo {
102
+ display: block;
103
+ width: 1.1em;
104
+ height: 1.1em;
105
+ margin-right: 0.2em;
106
+ }
107
+
108
+ .amount {
109
+ font-family: 'dinm';
110
+ }
111
+
112
+ .currency-name {
113
+ margin-left: 0.2em;
114
+ }
115
+
116
+ .unit {
117
+ display: inline-block;
118
+ margin-left: 0.2em;
119
+ }
120
+ }
121
+ </style>
@@ -1,26 +1,26 @@
1
- <script setup lang="ts">
2
- import { computed } from 'vue';
3
-
4
- const props = defineProps<{
5
- seconds: number
6
- }>();
7
-
8
- const formattedDuration = computed(() => {
9
- const days = Math.floor(props.seconds / (3600 * 24));
10
- const hours = Math.floor((props.seconds % (3600 * 24)) / 3600);
11
- const minutes = Math.floor((props.seconds % 3600) / 60);
12
- const seconds = props.seconds % 60;
13
- let formattedDuration = '';
14
-
15
- days >= 1 && (formattedDuration += `${Math.floor(days)}天 `);
16
- hours >= 1 && (formattedDuration += `${Math.floor(hours)}小时 `);
17
- minutes >= 1 && (formattedDuration += `${Math.floor(minutes)}分钟 `);
18
- seconds >= 1 && (formattedDuration += `${Math.floor(seconds)}秒`);
19
-
20
- return formattedDuration;
21
- });
22
- </script>
23
-
24
- <template>
25
- <span>{{ formattedDuration }}</span>
26
- </template>
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue';
3
+
4
+ const props = defineProps<{
5
+ seconds: number
6
+ }>();
7
+
8
+ const formattedDuration = computed(() => {
9
+ const days = Math.floor(props.seconds / (3600 * 24));
10
+ const hours = Math.floor((props.seconds % (3600 * 24)) / 3600);
11
+ const minutes = Math.floor((props.seconds % 3600) / 60);
12
+ const seconds = props.seconds % 60;
13
+ let formattedDuration = '';
14
+
15
+ days >= 1 && (formattedDuration += `${Math.floor(days)}天 `);
16
+ hours >= 1 && (formattedDuration += `${Math.floor(hours)}小时 `);
17
+ minutes >= 1 && (formattedDuration += `${Math.floor(minutes)}分钟 `);
18
+ seconds >= 1 && (formattedDuration += `${Math.floor(seconds)}秒`);
19
+
20
+ return formattedDuration;
21
+ });
22
+ </script>
23
+
24
+ <template>
25
+ <span>{{ formattedDuration }}</span>
26
+ </template>
@@ -1,51 +1,51 @@
1
- <script setup lang="ts">
2
- import { Tooltip as ATooltip, TypographyLink as ATypographyLink } from 'ant-design-vue';
3
- import { computed } from 'vue';
4
- import { desensitize, getScanBrowser } from '../../../../utils';
5
-
6
- type HashType = Parameters<typeof getScanBrowser>[2];
7
-
8
- defineOptions({
9
- inheritAttrs: false,
10
- });
11
-
12
- const props = withDefaults(
13
- defineProps<{
14
- hash: string
15
- hide?: boolean
16
- chain?: string
17
- type?: HashType
18
- empty?: string
19
- }>(),
20
- {
21
- hide: true,
22
- type: 'transaction',
23
- empty: '-',
24
- },
25
- );
26
-
27
- const href = computed(() => {
28
- const { hash, chain, type } = props;
29
-
30
- if (!hash || !chain || !type)
31
- return;
32
- return getScanBrowser(chain, hash, type);
33
- });
34
- const text = computed(() => {
35
- if (props.hash)
36
- return props.hide ? desensitize(props.hash) : props.hash;
37
- else
38
- return props.empty;
39
- });
40
- </script>
41
-
42
- <template>
43
- <ATypographyLink :href="href" :copyable="{ text: props.hash, tooltip: false }" target="_blank">
44
- <ATooltip>
45
- <template v-if="props.hide" #title>
46
- <span class="font-mono">{{ props.hash }}</span>
47
- </template>
48
- <span v-bind="$attrs"><slot><span class="font-mono">{{ text }}</span></slot></span>
49
- </ATooltip>
50
- </ATypographyLink>
51
- </template>
1
+ <script setup lang="ts">
2
+ import { Tooltip as ATooltip, TypographyLink as ATypographyLink } from 'ant-design-vue';
3
+ import { computed } from 'vue';
4
+ import { desensitize, getScanBrowser } from '../../../../utils';
5
+
6
+ type HashType = Parameters<typeof getScanBrowser>[2];
7
+
8
+ defineOptions({
9
+ inheritAttrs: false,
10
+ });
11
+
12
+ const props = withDefaults(
13
+ defineProps<{
14
+ hash: string
15
+ hide?: boolean
16
+ chain?: string
17
+ type?: HashType
18
+ empty?: string
19
+ }>(),
20
+ {
21
+ hide: true,
22
+ type: 'transaction',
23
+ empty: '-',
24
+ },
25
+ );
26
+
27
+ const href = computed(() => {
28
+ const { hash, chain, type } = props;
29
+
30
+ if (!hash || !chain || !type)
31
+ return;
32
+ return getScanBrowser(chain, hash, type);
33
+ });
34
+ const text = computed(() => {
35
+ if (props.hash)
36
+ return props.hide ? desensitize(props.hash) : props.hash;
37
+ else
38
+ return props.empty;
39
+ });
40
+ </script>
41
+
42
+ <template>
43
+ <ATypographyLink :href="href" :copyable="{ text: props.hash, tooltip: false }" target="_blank">
44
+ <ATooltip>
45
+ <template v-if="props.hide" #title>
46
+ <span class="font-mono">{{ props.hash }}</span>
47
+ </template>
48
+ <span v-bind="$attrs"><slot><span class="font-mono">{{ text }}</span></slot></span>
49
+ </ATooltip>
50
+ </ATypographyLink>
51
+ </template>
@@ -1,13 +1,13 @@
1
- import { computed, h } from 'vue';
2
- import { Tag as ATag } from 'ant-design-vue';
3
- import type { TagProps } from 'ant-design-vue';
4
-
5
- export function createTagGetter(typeMapFn: () => { [code: number | string]: [ text: string, color: TagProps['color'] ] }) {
6
- const typeMap = computed(typeMapFn);
7
-
8
- return (type: number | string) => {
9
- const [text, color] = typeMap.value[type] ?? [];
10
-
11
- return text ? h(ATag, { color }, () => text) : h('span', null, '-');
12
- };
13
- }
1
+ import { computed, h } from 'vue';
2
+ import { Tag as ATag } from 'ant-design-vue';
3
+ import type { TagProps } from 'ant-design-vue';
4
+
5
+ export function createTagGetter(typeMapFn: () => { [code: number | string]: [ text: string, color: TagProps['color'] ] }) {
6
+ const typeMap = computed(typeMapFn);
7
+
8
+ return (type: number | string) => {
9
+ const [text, color] = typeMap.value[type] ?? [];
10
+
11
+ return text ? h(ATag, { color }, () => text) : h('span', null, '-');
12
+ };
13
+ }
@@ -1,2 +1,3 @@
1
1
  export { default as PictureCardUpload } from './src/PictureCardUpload.vue';
2
2
  export { createAwsS3Request } from './src/customRequests';
3
+ export { getFileNameByUrl, isFilesDoneFn, urlToUploadFile } from './src/helpers';
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { message } from 'ant-design-vue';
2
+ import { Image as AImage, ImagePreviewGroup as AImagePreviewGroup, Upload as AUpload, message } from 'ant-design-vue';
3
3
  import type { UploadProps } from 'ant-design-vue';
4
4
  import type { PreviewGroupPreview } from 'ant-design-vue/es/vc-image/src/PreviewGroup';
5
5
  import { useVModel } from '@vueuse/core';
@@ -0,0 +1,37 @@
1
+ import type { UploadFile } from 'ant-design-vue/es/upload';
2
+ import { type Ref, computed } from 'vue';
3
+
4
+ /**
5
+ * 获取URL中的文件名
6
+ * @param url - 文件的URL
7
+ * @returns 文件名
8
+ */
9
+ export function getFileNameByUrl(url: string) {
10
+ return url.split('/').pop();
11
+ }
12
+
13
+ /**
14
+ * 判断文件是否全部上传完成
15
+ * @param files - 上传文件的引用
16
+ * @returns 如果所有文件都已完成上传,则返回 true;否则返回 false
17
+ */
18
+ export function isFilesDoneFn(files: Ref<UploadFile[] | undefined>) {
19
+ return computed(() => files.value ? files.value.every(file => file.status === 'done') : true);
20
+ }
21
+
22
+ /**
23
+ * 将URL转换为上传文件对象数组
24
+ * @param urls 要转换的URL数组或URL字符串
25
+ * @returns 上传文件对象数组
26
+ */
27
+ export function urlToUploadFile(urls?: string[] | string) {
28
+ const _urls = urls ? Array.isArray(urls) ? urls : [urls] : [];
29
+ const files = _urls.filter(url => !!url).map(url => ({
30
+ uid: getFileNameByUrl(url),
31
+ name: getFileNameByUrl(url),
32
+ status: 'done',
33
+ url,
34
+ }));
35
+
36
+ return files;
37
+ }
@@ -10,6 +10,7 @@ const UNWATCH_NAME = `v-${PLUGIN_NAME}@unwatch`;
10
10
  export function setupPermissionPlugin(app: App) {
11
11
  app.directive<HTMLElement, TCodes>(PLUGIN_NAME, {
12
12
  mounted(el, binding) {
13
+ console.log('🤡 / el:', el);
13
14
  const permissionStore = adminPlugin.deps.usePermissionStore();
14
15
 
15
16
  function updateVisibility() {
@@ -1,3 +1,3 @@
1
- export { setupPageProgress } from './pageProgress';
2
- export { setupPageTitle } from './pageTitle';
3
- export { setupCollapseMenu } from './collapseMenu';
1
+ export { setupPageProgress } from './pageProgress';
2
+ export { setupPageTitle } from './pageTitle';
3
+ export { setupCollapseMenu } from './collapseMenu';
@@ -1,27 +1,27 @@
1
- import type { Router } from 'vue-router';
2
- import { useStyleTag } from '@vueuse/core';
3
- import NProgress from 'nprogress';
4
- import 'nprogress/nprogress.css';
5
-
6
- /**
7
- * 用于显示页面跳转时,页面顶部进度条
8
- */
9
- export function setupPageProgress(router: Router) {
10
- NProgress.configure({ showSpinner: false });
11
- useStyleTag(`
12
- #nprogress .bar {
13
- height: 3px;
14
- background: var(--antd-colorPrimary);
15
- }
16
- #nprogress .peg {
17
- box-shadow: 0 0 10px var(--antd-colorPrimary), 0 0 5px var(--antd-colorPrimary);
18
- }
19
- `);
20
-
21
- router.beforeEach(() => {
22
- NProgress.start();
23
- });
24
- router.afterEach(() => {
25
- setTimeout(() => NProgress.done(), 200);
26
- });
27
- }
1
+ import type { Router } from 'vue-router';
2
+ import { useStyleTag } from '@vueuse/core';
3
+ import NProgress from 'nprogress';
4
+ import 'nprogress/nprogress.css';
5
+
6
+ /**
7
+ * 用于显示页面跳转时,页面顶部进度条
8
+ */
9
+ export function setupPageProgress(router: Router) {
10
+ NProgress.configure({ showSpinner: false });
11
+ useStyleTag(`
12
+ #nprogress .bar {
13
+ height: 3px;
14
+ background: var(--antd-colorPrimary);
15
+ }
16
+ #nprogress .peg {
17
+ box-shadow: 0 0 10px var(--antd-colorPrimary), 0 0 5px var(--antd-colorPrimary);
18
+ }
19
+ `);
20
+
21
+ router.beforeEach(() => {
22
+ NProgress.start();
23
+ });
24
+ router.afterEach(() => {
25
+ setTimeout(() => NProgress.done(), 200);
26
+ });
27
+ }
@@ -21,9 +21,7 @@ interface IBreadcrumb {
21
21
  }
22
22
 
23
23
  function createUsePageStore() {
24
- return defineStore('appPage', () => {
25
- return storeSetup();
26
- });
24
+ return defineStore('appPage', () => storeSetup());
27
25
  }
28
26
 
29
27
  function storeSetup() {
@@ -173,6 +173,23 @@
173
173
  }
174
174
  }
175
175
 
176
+ // ACard 组件的 actions 右对齐
177
+ .ant-card.antd-cover__actions-right-align {
178
+ .ant-card-actions {
179
+ justify-content: flex-end !important;
180
+ padding: 0 24px;
181
+
182
+ > li {
183
+ width: auto !important;
184
+ border-inline-end: none !important;
185
+
186
+ &:not(:last-child) {
187
+ margin-right: 8px;
188
+ }
189
+ }
190
+ }
191
+ }
192
+
176
193
  // 查询器表单基本样式
177
194
  .ant-form.ant-form__filter {
178
195
  display: flex;