@peng_kai/kit 0.2.47 → 0.3.0-beta.1

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,153 +1,153 @@
1
- <script lang="ts" setup>
2
- import { computed, ref } from 'vue';
3
- import { Button as AButton, Drawer as ADrawer, Dropdown as ADropdown } from 'ant-design-vue';
4
-
5
- defineOptions({
6
- inheritAttrs: false,
7
- });
8
-
9
- const props = withDefaults(defineProps<{
10
- loading?: boolean
11
- filterQuery?: any
12
- filterParams?: any
13
- filterForm?: any
14
- }>(), {
15
- loading: undefined,
16
- });
17
- const emits = defineEmits<{
18
- (e: 'filter'): void
19
- (e: 'reset', value: number): void
20
- }>();
21
-
22
- const filterVisible = ref(false);
23
- const loading = computed(() => {
24
- const _loading1 = props.loading;
25
- const _loading2: boolean = props.filterQuery?.isFetching.value;
26
-
27
- if (_loading1 === undefined && _loading2 === undefined)
28
- return false;
29
-
30
- if (_loading1 !== undefined)
31
- return _loading1;
32
-
33
- return _loading2;
34
- });
35
-
36
- function filter() {
37
- props.filterParams?.update?.();
38
- emits('filter');
39
- filterVisible.value = false;
40
- }
41
-
42
- function reset() {
43
- props.filterForm?.$form.resetFields?.();
44
- props.filterParams?.update?.();
45
- emits('reset', 1);
46
- filterVisible.value = false;
47
- }
48
- </script>
49
-
50
- <template>
51
- <div class="p-3 bg-$antd-colorBgContainer text-14px rounded-2" v-bind="$attrs">
52
- <!-- .filter-params 为空时显示 .filter-params-tips -->
53
-
54
- <div class="m--3 p-3" @click="filterVisible = true">
55
- <div class="filter-params">
56
- <slot name="params" />
57
- </div>
58
- <div class="filter-params-tips">
59
- 条件筛选,点击打开
60
- </div>
61
- </div>
62
-
63
- <!-- 操作区 -->
64
- <div v-if="$slots.actions || $slots.moreActions" class="actions">
65
- <slot name="actions" />
66
-
67
- <ADropdown v-if="$slots.moreActions" trigger="click" destroyPopupOnHide>
68
- <AButton type="link" size="small">
69
- 更多
70
- </AButton>
71
- <template #overlay>
72
- <slot name="moreActions" />
73
- </template>
74
- </ADropdown>
75
- </div>
76
- </div>
77
-
78
- <ADrawer
79
- v-model:open="filterVisible" class="filter-drawer" placement="bottom"
80
- height="50vh"
81
- >
82
- <template #extra>
83
- <AButton class="mr-3 my--3" :disabled="loading" @click="reset()">
84
- 重置
85
- </AButton>
86
- <AButton class="my--3" type="primary" :loading="loading" @click="filter()">
87
- 筛选
88
- </AButton>
89
- </template>
90
- <template #default>
91
- <slot />
92
- </template>
93
- </ADrawer>
94
- </template>
95
-
96
- <style scoped lang="scss">
97
- .filter-params {
98
- display: flex;
99
- flex-wrap: wrap;
100
- justify-content: flex-start;
101
- gap: 5px 15px;
102
- }
103
-
104
- // .filter-params 为空时显示 .filter-params-tips
105
- .filter-params-tips {
106
- display: none;
107
- color: theme('colors.gray.DEFAULT');
108
- }
109
-
110
- .filter-params:empty {
111
- display: none;
112
- }
113
-
114
- .filter-params:empty + .filter-params-tips {
115
- display: block;
116
- }
117
-
118
- .actions {
119
- display: flex;
120
- align-items: center;
121
- justify-content: flex-end;
122
- border-top: 1px solid var(--antd-colorBorderSecondary);
123
- margin-top: 0.75rem;
124
- padding-top: 0.75rem;
125
- }
126
- </style>
127
-
128
- <style lang="scss">
129
- .filter-drawer {
130
- .ant-drawer-header {
131
- padding: 16px;
132
-
133
- .ant-drawer-close {
134
- --expand: 5px;
135
-
136
- padding: var(--expand);
137
- margin: calc(var(--expand) * -1) var(--expand) calc(var(--expand) * -1) 0;
138
- }
139
- }
140
-
141
- .ant-drawer-body {
142
- padding: 16px;
143
- }
144
-
145
- .ant-form-item {
146
- margin-bottom: 0;
147
-
148
- .ant-form-item-label {
149
- padding-bottom: 0;
150
- }
151
- }
152
- }
153
- </style>
1
+ <script lang="ts" setup>
2
+ import { computed, ref } from 'vue';
3
+ import { Button as AButton, Drawer as ADrawer, Dropdown as ADropdown } from 'ant-design-vue';
4
+
5
+ defineOptions({
6
+ inheritAttrs: false,
7
+ });
8
+
9
+ const props = withDefaults(defineProps<{
10
+ loading?: boolean
11
+ filterQuery?: any
12
+ filterParams?: any
13
+ filterForm?: any
14
+ }>(), {
15
+ loading: undefined,
16
+ });
17
+ const emits = defineEmits<{
18
+ (e: 'filter'): void
19
+ (e: 'reset', value: number): void
20
+ }>();
21
+
22
+ const filterVisible = ref(false);
23
+ const loading = computed(() => {
24
+ const _loading1 = props.loading;
25
+ const _loading2: boolean = props.filterQuery?.isFetching.value;
26
+
27
+ if (_loading1 === undefined && _loading2 === undefined)
28
+ return false;
29
+
30
+ if (_loading1 !== undefined)
31
+ return _loading1;
32
+
33
+ return _loading2;
34
+ });
35
+
36
+ function filter() {
37
+ props.filterParams?.update?.();
38
+ emits('filter');
39
+ filterVisible.value = false;
40
+ }
41
+
42
+ function reset() {
43
+ props.filterForm?.$form.resetFields?.();
44
+ props.filterParams?.update?.();
45
+ emits('reset', 1);
46
+ filterVisible.value = false;
47
+ }
48
+ </script>
49
+
50
+ <template>
51
+ <div class="p-3 bg-$antd-colorBgContainer text-14px rounded-2" v-bind="$attrs">
52
+ <!-- .filter-params 为空时显示 .filter-params-tips -->
53
+
54
+ <div class="m--3 p-3" @click="filterVisible = true">
55
+ <div class="filter-params">
56
+ <slot name="params" />
57
+ </div>
58
+ <div class="filter-params-tips">
59
+ 条件筛选,点击打开
60
+ </div>
61
+ </div>
62
+
63
+ <!-- 操作区 -->
64
+ <div v-if="$slots.actions || $slots.moreActions" class="actions">
65
+ <slot name="actions" />
66
+
67
+ <ADropdown v-if="$slots.moreActions" trigger="click" destroyPopupOnHide>
68
+ <AButton type="link" size="small">
69
+ 更多
70
+ </AButton>
71
+ <template #overlay>
72
+ <slot name="moreActions" />
73
+ </template>
74
+ </ADropdown>
75
+ </div>
76
+ </div>
77
+
78
+ <ADrawer
79
+ v-model:open="filterVisible" class="filter-drawer" placement="bottom"
80
+ height="50vh"
81
+ >
82
+ <template #extra>
83
+ <AButton class="mr-3 my--3" :disabled="loading" @click="reset()">
84
+ 重置
85
+ </AButton>
86
+ <AButton class="my--3" type="primary" :loading="loading" @click="filter()">
87
+ 筛选
88
+ </AButton>
89
+ </template>
90
+ <template #default>
91
+ <slot />
92
+ </template>
93
+ </ADrawer>
94
+ </template>
95
+
96
+ <style scoped lang="scss">
97
+ .filter-params {
98
+ display: flex;
99
+ flex-wrap: wrap;
100
+ justify-content: flex-start;
101
+ gap: 5px 15px;
102
+ }
103
+
104
+ // .filter-params 为空时显示 .filter-params-tips
105
+ .filter-params-tips {
106
+ display: none;
107
+ color: theme('colors.gray.DEFAULT');
108
+ }
109
+
110
+ .filter-params:empty {
111
+ display: none;
112
+ }
113
+
114
+ .filter-params:empty + .filter-params-tips {
115
+ display: block;
116
+ }
117
+
118
+ .actions {
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: flex-end;
122
+ border-top: 1px solid var(--antd-colorBorderSecondary);
123
+ margin-top: 0.75rem;
124
+ padding-top: 0.75rem;
125
+ }
126
+ </style>
127
+
128
+ <style lang="scss">
129
+ .filter-drawer {
130
+ .ant-drawer-header {
131
+ padding: 16px;
132
+
133
+ .ant-drawer-close {
134
+ --expand: 5px;
135
+
136
+ padding: var(--expand);
137
+ margin: calc(var(--expand) * -1) var(--expand) calc(var(--expand) * -1) 0;
138
+ }
139
+ }
140
+
141
+ .ant-drawer-body {
142
+ padding: 16px;
143
+ }
144
+
145
+ .ant-form-item {
146
+ margin-bottom: 0;
147
+
148
+ .ant-form-item-label {
149
+ padding-bottom: 0;
150
+ }
151
+ }
152
+ }
153
+ </style>
@@ -1 +1 @@
1
- export { default as ScrollNav } from './src/ScrollNav.vue';
1
+ export { default as ScrollNav } from './src/ScrollNav.vue';
@@ -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,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,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
+ }
@@ -1,54 +1,54 @@
1
- :root {
2
- // table 组件头部圆角设为 0
3
- .ant-table-wrapper {
4
- .ant-table .ant-table-header,
5
- table,
6
- .ant-table-container table > thead > tr:first-child > *:first-child,
7
- .ant-table-container table > thead > tr:first-child > *:last-child {
8
- border-radius: 0;
9
- }
10
-
11
- .ant-pagination {
12
- margin-bottom: 0;
13
- }
14
- }
15
-
16
-
17
- // 隐藏在 sticky 模式下的滚动条
18
- .ant-table-sticky-scroll {
19
- display: none;
20
- }
21
-
22
- // 卡片
23
- .ant-card .ant-card-actions > li > span {
24
- cursor: inherit;
25
- }
26
-
27
- // Tab 溢出出现下列框时
28
- .ant-tabs-dropdown-menu-title-content {
29
- display: flex;
30
- align-items: center;
31
- justify-content: space-between;
32
- }
33
-
34
- // 表格
35
- .ant-table-wrapper {
36
- .ant-table-row-expand-icon-collapsed::before {
37
- height: 1.5px;
38
- }
39
- .ant-table-row-expand-icon-collapsed::after {
40
- width: 1.5px;
41
- }
42
- }
43
-
44
- .ant-drawer {
45
- &:focus {
46
- outline: none;
47
- }
48
-
49
- &.ant-drawer-bottom .ant-drawer-content {
50
- border-top-left-radius: 8px;
51
- border-top-right-radius: 8px;
52
- }
53
- }
54
- }
1
+ :root {
2
+ // table 组件头部圆角设为 0
3
+ .ant-table-wrapper {
4
+ .ant-table .ant-table-header,
5
+ table,
6
+ .ant-table-container table > thead > tr:first-child > *:first-child,
7
+ .ant-table-container table > thead > tr:first-child > *:last-child {
8
+ border-radius: 0;
9
+ }
10
+
11
+ .ant-pagination {
12
+ margin-bottom: 0;
13
+ }
14
+ }
15
+
16
+
17
+ // 隐藏在 sticky 模式下的滚动条
18
+ .ant-table-sticky-scroll {
19
+ display: none;
20
+ }
21
+
22
+ // 卡片
23
+ .ant-card .ant-card-actions > li > span {
24
+ cursor: inherit;
25
+ }
26
+
27
+ // Tab 溢出出现下列框时
28
+ .ant-tabs-dropdown-menu-title-content {
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: space-between;
32
+ }
33
+
34
+ // 表格
35
+ .ant-table-wrapper {
36
+ .ant-table-row-expand-icon-collapsed::before {
37
+ height: 1.5px;
38
+ }
39
+ .ant-table-row-expand-icon-collapsed::after {
40
+ width: 1.5px;
41
+ }
42
+ }
43
+
44
+ .ant-drawer {
45
+ &:focus {
46
+ outline: none;
47
+ }
48
+
49
+ &.ant-drawer-bottom .ant-drawer-content {
50
+ border-top-left-radius: 8px;
51
+ border-top-right-radius: 8px;
52
+ }
53
+ }
54
+ }
@@ -1,36 +1,36 @@
1
- import type { App } from 'vue';
2
-
3
- export function formLabelAlign(app: App) {
4
- const directiveName = 'antd-form-label-align';
5
- const resizeObserverKey = `${directiveName}@resizeObserver`;
6
-
7
- function init(el: HTMLElement) {
8
- const labels = el.querySelectorAll('.ant-form-item .ant-form-item-label');
9
- const resizeObserver = new ResizeObserver((entries) => {
10
- const widths = entries.map(e => e.borderBoxSize?.[0]?.inlineSize ?? 0);
11
- const maxWidth = Math.max(...widths);
12
-
13
- if (maxWidth <= 0)
14
- return;
15
-
16
- el.style.setProperty('--max-label-width', `${maxWidth}px`);
17
- entries.forEach((e) => {
18
- const target = e.target as HTMLElement;
19
- target.style.setProperty('width', 'var(--max-label-width)');
20
- });
21
- });
22
-
23
- Array.from(labels).forEach(label => resizeObserver.observe(label));
24
-
25
- return resizeObserver;
26
- }
27
-
28
- app.directive(directiveName, {
29
- mounted(el: HTMLElement) {
30
- (el as any)[resizeObserverKey] = init(el);
31
- },
32
- updated(el) {
33
- (el as any)[resizeObserverKey] = init(el);
34
- },
35
- });
36
- }
1
+ import type { App } from 'vue';
2
+
3
+ export function formLabelAlign(app: App) {
4
+ const directiveName = 'antd-form-label-align';
5
+ const resizeObserverKey = `${directiveName}@resizeObserver`;
6
+
7
+ function init(el: HTMLElement) {
8
+ const labels = el.querySelectorAll('.ant-form-item .ant-form-item-label');
9
+ const resizeObserver = new ResizeObserver((entries) => {
10
+ const widths = entries.map(e => e.borderBoxSize?.[0]?.inlineSize ?? 0);
11
+ const maxWidth = Math.max(...widths);
12
+
13
+ if (maxWidth <= 0)
14
+ return;
15
+
16
+ el.style.setProperty('--max-label-width', `${maxWidth}px`);
17
+ entries.forEach((e) => {
18
+ const target = e.target as HTMLElement;
19
+ target.style.setProperty('width', 'var(--max-label-width)');
20
+ });
21
+ });
22
+
23
+ Array.from(labels).forEach(label => resizeObserver.observe(label));
24
+
25
+ return resizeObserver;
26
+ }
27
+
28
+ app.directive(directiveName, {
29
+ mounted(el: HTMLElement) {
30
+ (el as any)[resizeObserverKey] = init(el);
31
+ },
32
+ updated(el) {
33
+ (el as any)[resizeObserverKey] = init(el);
34
+ },
35
+ });
36
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@peng_kai/kit",
3
3
  "type": "module",
4
- "version": "0.2.47",
4
+ "version": "0.3.0-beta.1",
5
5
  "description": "",
6
6
  "author": "",
7
7
  "license": "ISC",
@@ -13,41 +13,41 @@
13
13
  "lint:fix": "eslint . --fix"
14
14
  },
15
15
  "peerDependencies": {
16
- "ant-design-vue": "4.2.3",
17
- "vue": "3.4.31",
18
- "vue-router": "4.4.0"
16
+ "ant-design-vue": "4.2.5",
17
+ "vue": "3.5.11",
18
+ "vue-router": "4.4.5"
19
19
  },
20
20
  "dependencies": {
21
- "@aws-sdk/client-s3": "^3.609.0",
22
- "@aws-sdk/lib-storage": "^3.609.0",
23
- "@babel/generator": "^7.24.7",
24
- "@babel/parser": "^7.24.7",
25
- "@babel/traverse": "^7.24.7",
26
- "@babel/types": "^7.24.7",
21
+ "@aws-sdk/client-s3": "^3.667.0",
22
+ "@aws-sdk/lib-storage": "^3.667.0",
23
+ "@babel/generator": "^7.25.7",
24
+ "@babel/parser": "^7.25.7",
25
+ "@babel/traverse": "^7.25.7",
26
+ "@babel/types": "^7.25.7",
27
27
  "@ckeditor/ckeditor5-vue": "^5.1.0",
28
- "@fingerprintjs/fingerprintjs": "^4.4.1",
29
- "@tanstack/vue-query": "^5.49.1",
30
- "@vueuse/components": "^10.11.0",
31
- "@vueuse/core": "^10.11.0",
32
- "@vueuse/router": "^10.11.0",
33
- "a-calc": "^1.3.12",
28
+ "@fingerprintjs/fingerprintjs": "^4.5.0",
29
+ "@tanstack/vue-query": "^5.59.1",
30
+ "@vueuse/components": "^11.1.0",
31
+ "@vueuse/core": "^11.1.0",
32
+ "@vueuse/router": "^11.1.0",
33
+ "a-calc": "^2.2.10",
34
34
  "archiver": "^7.0.1",
35
- "axios": "^1.7.2",
35
+ "axios": "^1.7.7",
36
36
  "bignumber.js": "^9.1.2",
37
37
  "chokidar": "^3.6.0",
38
38
  "crypto-es": "^2.1.0",
39
- "dayjs": "^1.11.11",
40
- "echarts": "^5.4.3",
41
- "execa": "^9.3.0",
39
+ "dayjs": "^1.11.13",
40
+ "echarts": "^5.5.1",
41
+ "execa": "^9.4.0",
42
42
  "fast-glob": "^3.3.2",
43
43
  "localstorage-slim": "^2.7.1",
44
44
  "lodash-es": "^4.17.21",
45
45
  "nprogress": "^0.2.0",
46
- "pinia": "^2.1.7",
46
+ "pinia": "^2.2.4",
47
47
  "tsx": "^4.16.00",
48
- "vue": "^3.4.31",
49
- "vue-i18n": "^9.13.1",
50
- "vue-router": "^4.4.0"
48
+ "vue": "^3.5.11",
49
+ "vue-i18n": "^10.0.4",
50
+ "vue-router": "^4.4.5"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@ckeditor/ckeditor5-adapter-ckfinder": "^41.1.0",
@@ -85,11 +85,11 @@
85
85
  "@types/archiver": "^6.0.2",
86
86
  "@types/crypto-js": "^4.2.2",
87
87
  "@types/lodash-es": "^4.17.12",
88
- "@types/node": "^18.19.39",
88
+ "@types/node": "^20.16.11",
89
89
  "@types/nprogress": "^0.2.3",
90
- "ant-design-vue": "^4.2.3",
91
- "type-fest": "^4.21.0",
92
- "typescript": "^5.5.3",
93
- "vue-component-type-helpers": "^2.0.24"
90
+ "ant-design-vue": "^4.2.5",
91
+ "type-fest": "^4.26.1",
92
+ "typescript": "^5.6.3",
93
+ "vue-component-type-helpers": "^2.1.6"
94
94
  }
95
95
  }
@@ -1,7 +1,7 @@
1
- module.exports = {
2
- // root: true,
3
- extends: ['@peng_kai/lint/vue/stylelint_v2'],
4
- rules: {
5
- 'custom-property-pattern': '(antd-([a-z][a-zA-Z0-9]+)*)|(([a-z][a-z0-9]*)(-[a-z0-9]+)*)',
6
- },
7
- };
1
+ module.exports = {
2
+ // root: true,
3
+ extends: ['@peng_kai/lint/vue/stylelint_v2'],
4
+ rules: {
5
+ 'custom-property-pattern': '(antd-([a-z][a-zA-Z0-9]+)*)|(([a-z][a-z0-9]*)(-[a-z0-9]+)*)',
6
+ },
7
+ };
package/utils/number.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { calc } from 'a-calc';
2
1
  import type { BigNumber } from 'bignumber.js';
3
2
  import bn from 'bignumber.js';
4
3
 
@@ -17,23 +16,50 @@ export { calc } from 'a-calc';
17
16
  */
18
17
  export const numFmt = {
19
18
  /** 保留18位小数,千位符 */
20
- t: (num: any, err: any = null) => calc('a | <=18 ,', { a: String(num), _error: err }) as string | null,
19
+ t: (num: any, fallback: any = 'NaN') => {
20
+ const result = bn(num);
21
+ return result.isNaN() ? fallback : result.toFormat(18);
22
+ },
21
23
  /** 舍去小数,四舍五入,千位符 */
22
- d0r5t: (num: any, err: any = null) => calc('a | =0 ~5 ,', { a: String(num), _error: err }) as string | null,
24
+ d0r5t: (num: any, fallback: any = 'NaN') => {
25
+ const result = bn(num);
26
+ return result.isNaN() ? fallback : result.decimalPlaces(0, bn.ROUND_HALF_UP).toFormat(0);
27
+ },
23
28
  /** 舍去小数,向下取整,千位符 */
24
- d0r0t: (num: any, err: any = null) => calc('a | =0 ~- ,', { a: String(num), _error: err }) as string | null,
29
+ d0r0t: (num: any, fallback: any = 'NaN') => {
30
+ const result = bn(num);
31
+ return result.isNaN() ? fallback : result.decimalPlaces(0, bn.ROUND_DOWN).toFormat(0);
32
+ },
25
33
  /** 保留2位小数,四舍五入,千位符 */
26
- d2r5t: (num: any, err: any = null) => calc('a | <=2 ~5 ,', { a: String(num), _error: err }) as string | null,
34
+ d2r5t: (num: any, fallback: any = 'NaN') => {
35
+ const result = bn(num);
36
+ return result.isNaN() ? fallback : result.decimalPlaces(2, bn.ROUND_HALF_UP).toFormat(2);
37
+ },
27
38
  /** 保留2位小数,向下取整,千位符 */
28
- d2r0t: (num: any, err: any = null) => calc('a | <=2 ~- ,', { a: String(num), _error: err }) as string | null,
39
+ d2r0t: (num: any, fallback: any = 'NaN') => {
40
+ const result = bn(num);
41
+ return result.isNaN() ? fallback : result.decimalPlaces(2, bn.ROUND_DOWN).toFormat(2);
42
+ },
29
43
  /** 保留6位小数,四舍五入,千位符 */
30
- d6r5t: (num: any, err: any = null) => calc('a | <=6 ~5 ,', { a: String(num), _error: err }) as string | null,
44
+ d6r5t: (num: any, fallback: any = 'NaN') => {
45
+ const result = bn(num);
46
+ return result.isNaN() ? fallback : result.decimalPlaces(6, bn.ROUND_HALF_UP).toFormat(6);
47
+ },
31
48
  /** 保留6位小数,向下取整,千位符 */
32
- d6r0t: (num: any, err: any = null) => calc('a | <=6 ~- ,', { a: String(num), _error: err }) as string | null,
49
+ d6r0t: (num: any, fallback: any = 'NaN') => {
50
+ const result = bn(num);
51
+ return result.isNaN() ? fallback : result.decimalPlaces(6, bn.ROUND_DOWN).toFormat(6);
52
+ },
33
53
  /** 保留8位小数,四舍五入,千位符 */
34
- d8r5t: (num: any, err: any = null) => calc('a | <=8 ~5 ,', { a: String(num), _error: err }) as string | null,
54
+ d8r5t: (num: any, fallback: any = 'NaN') => {
55
+ const result = bn(num);
56
+ return result.isNaN() ? fallback : result.decimalPlaces(8, bn.ROUND_HALF_UP).toFormat(8);
57
+ },
35
58
  /** 保留8位小数,向下取整,千位符 */
36
- d8r0t: (num: any, err: any = null) => calc('a | <=8 ~- ,', { a: String(num), _error: err }) as string | null,
59
+ d8r0t: (num: any, fallback: any = 'NaN') => {
60
+ const result = bn(num);
61
+ return result.isNaN() ? fallback : result.decimalPlaces(8, bn.ROUND_DOWN).toFormat(8);
62
+ },
37
63
  };
38
64
 
39
65
  /**
@@ -43,7 +69,7 @@ export const numFmt = {
43
69
  * @returns 金额的格式化字符串表示。
44
70
  */
45
71
  export function toAmount(amount: any, decimal: string | number = 0) {
46
- const res = calc('a / 10 ** d', { a: String(amount), d: Number(decimal), _error: null });
72
+ const res = bn(amount).div(bn(10).pow(Number(decimal)));
47
73
  const fmt = (fmt: keyof typeof numFmt) => (numFmt[fmt] ?? numFmt.t)(res);
48
74
  fmt.toString = () => numFmt.t(res);
49
75
 
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { useEventListener, useResizeObserver } from '@vueuse/core';
3
3
  import * as echarts from 'echarts';
4
- import { onBeforeMount, onMounted, ref, shallowRef, toRef, watch, watchEffect } from 'vue';
4
+ import { onBeforeMount, onMounted, ref, shallowRef, toRef, watch } from 'vue';
5
5
  import { useIsDark } from '../../../hooks/useIsDark';
6
6
  </script>
7
7
 
@@ -9,8 +9,10 @@ import { useIsDark } from '../../../hooks/useIsDark';
9
9
  const props = withDefaults(defineProps<{
10
10
  echartOption: any
11
11
  theme?: 'light' | 'dark' | 'auto'
12
+ updateMode?: 'all' | 'data'
12
13
  }>(), {
13
14
  theme: 'auto',
15
+ updateMode: 'all',
14
16
  });
15
17
 
16
18
  const $chartEle = ref<HTMLElement>();
@@ -38,22 +40,31 @@ function getTheme() {
38
40
  return props.theme;
39
41
  }
40
42
 
41
- watch(toRef(props, 'echartOption'), (option) => {
43
+ function updateAll(option: any) {
44
+ echartInst.value?.dispose();
45
+ echartInst.value = null;
46
+ echartInst.value = echarts.init($chartEle.value, getTheme());
47
+ echartInst.value.setOption(option ?? {});
48
+ }
49
+
50
+ function updateData(option: any) {
42
51
  echartInst.value?.setOption(option ?? {});
52
+ }
53
+
54
+ watch(toRef(props, 'echartOption'), (option) => {
55
+ if (props.updateMode === 'all')
56
+ updateAll(option);
57
+ else
58
+ updateData(option);
43
59
  });
44
60
 
45
61
  watch(isDark, () => {
46
- if (props.theme === 'auto') {
47
- echartInst.value?.dispose();
48
- echartInst.value = null;
49
- echartInst.value = echarts.init($chartEle.value, getTheme());
50
- echartInst.value.setOption(props.echartOption ?? {});
51
- }
62
+ if (props.theme === 'auto')
63
+ updateAll(props.echartOption);
52
64
  });
53
65
 
54
66
  onMounted(() => {
55
- echartInst.value = echarts.init($chartEle.value, getTheme());
56
- echartInst.value.setOption(props.echartOption ?? {});
67
+ updateAll(props.echartOption ?? {});
57
68
  });
58
69
 
59
70
  onBeforeMount(() => {
@@ -1 +1 @@
1
- export { default as InfiniteQuery } from './src/InfiniteQuery.vue';
1
+ export { default as InfiniteQuery } from './src/InfiniteQuery.vue';
@@ -1,39 +1,39 @@
1
- import { onUnmounted, watch } from 'vue';
2
- import type { Ref } from 'vue';
3
- import { useIntersectionObserver, useIntervalFn } from '@vueuse/core';
4
-
5
- export function useCreateTrigger(containerEle: Ref<HTMLElement | undefined>, callback: Function, distance: string) {
6
- const triggerEl = document.createElement('div');
7
-
8
- Object.assign(triggerEl.style, {
9
- position: 'relative',
10
- zIndex: '5',
11
- marginTop: `-${distance}`,
12
- marginBottom: distance,
13
- width: '5px',
14
- height: '5px',
15
- // background: 'red',
16
- } satisfies Partial<CSSStyleDeclaration>);
17
-
18
- useIntervalFn(() => {
19
- const { transform } = triggerEl.style;
20
-
21
- if (transform)
22
- triggerEl.style.removeProperty('transform');
23
- else triggerEl.style.setProperty('transform', 'translateX(-200%)');
24
- }, 500);
25
-
26
- useIntersectionObserver(triggerEl, ([entry]) => {
27
- if (entry.isIntersecting)
28
- callback();
29
- });
30
-
31
- watch(containerEle, (ele) => {
32
- if (ele)
33
- ele.append(triggerEl);
34
- });
35
-
36
- onUnmounted(() => {
37
- triggerEl.remove();
38
- });
39
- }
1
+ import { onUnmounted, watch } from 'vue';
2
+ import type { Ref } from 'vue';
3
+ import { useIntersectionObserver, useIntervalFn } from '@vueuse/core';
4
+
5
+ export function useCreateTrigger(containerEle: Ref<HTMLElement | undefined>, callback: Function, distance: string) {
6
+ const triggerEl = document.createElement('div');
7
+
8
+ Object.assign(triggerEl.style, {
9
+ position: 'relative',
10
+ zIndex: '5',
11
+ marginTop: `-${distance}`,
12
+ marginBottom: distance,
13
+ width: '5px',
14
+ height: '5px',
15
+ // background: 'red',
16
+ } satisfies Partial<CSSStyleDeclaration>);
17
+
18
+ useIntervalFn(() => {
19
+ const { transform } = triggerEl.style;
20
+
21
+ if (transform)
22
+ triggerEl.style.removeProperty('transform');
23
+ else triggerEl.style.setProperty('transform', 'translateX(-200%)');
24
+ }, 500);
25
+
26
+ useIntersectionObserver(triggerEl, ([entry]) => {
27
+ if (entry.isIntersecting)
28
+ callback();
29
+ });
30
+
31
+ watch(containerEle, (ele) => {
32
+ if (ele)
33
+ ele.append(triggerEl);
34
+ });
35
+
36
+ onUnmounted(() => {
37
+ triggerEl.remove();
38
+ });
39
+ }