create-weapp-vite 2.0.4 → 2.0.6
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/{chunk-CJ5B2GYK.js → chunk-IOT6Y2QU.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/templates/wevu-tdesign/src/components/QuickActionGrid/index.vue +5 -15
- package/templates/wevu-tdesign/src/hooks/useDialog.ts +32 -0
- package/templates/wevu-tdesign/src/hooks/useFormBinder.ts +17 -0
- package/templates/wevu-tdesign/src/hooks/usePullDownRefresh.ts +11 -0
- package/templates/wevu-tdesign/src/hooks/useToast.ts +34 -0
- package/templates/wevu-tdesign/src/pages/ability/index.vue +6 -21
- package/templates/wevu-tdesign/src/pages/form/index.vue +5 -22
- package/templates/wevu-tdesign/src/pages/index/index.vue +8 -23
- package/templates/wevu-tdesign/src/pages/list/index.vue +11 -41
- package/templates/wevu-tdesign/src/types/action.ts +14 -0
- package/templates/wevu-tdesign/src/types/list.ts +17 -0
- package/templates/wevu-tdesign/src/utils/listFilters.ts +34 -0
|
@@ -5,10 +5,10 @@ import fs2 from "fs-extra";
|
|
|
5
5
|
import path2 from "pathe";
|
|
6
6
|
|
|
7
7
|
// ../weapp-vite/package.json
|
|
8
|
-
var version = "6.
|
|
8
|
+
var version = "6.3.0";
|
|
9
9
|
|
|
10
10
|
// ../wevu/package.json
|
|
11
|
-
var version2 = "1.1.
|
|
11
|
+
var version2 = "1.1.3";
|
|
12
12
|
|
|
13
13
|
// src/enums.ts
|
|
14
14
|
var TemplateName = /* @__PURE__ */ ((TemplateName2) => {
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-weapp-vite",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.6",
|
|
5
5
|
"description": "create-weapp-vite",
|
|
6
6
|
"author": "ice breaker <1324318532@qq.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"fs-extra": "^11.3.3",
|
|
40
40
|
"pathe": "^2.0.3",
|
|
41
41
|
"pkg-types": "^2.3.0",
|
|
42
|
-
"@weapp-core/logger": "^3.0.
|
|
42
|
+
"@weapp-core/logger": "^3.0.1"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"dev": "tsup --watch --sourcemap",
|
|
@@ -1,38 +1,28 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { QuickActionItem } from '@/types/action'
|
|
3
|
+
|
|
2
4
|
import { computed } from 'wevu'
|
|
3
5
|
|
|
4
6
|
const props = withDefaults(defineProps<{
|
|
5
7
|
title: string
|
|
6
8
|
subtitle?: string
|
|
7
|
-
items?:
|
|
9
|
+
items?: QuickActionItem[]
|
|
8
10
|
}>(), {
|
|
9
11
|
subtitle: '',
|
|
10
12
|
items: () => [],
|
|
11
13
|
})
|
|
12
14
|
|
|
13
15
|
const emit = defineEmits<{
|
|
14
|
-
(e: 'select', item:
|
|
16
|
+
(e: 'select', item: QuickActionItem): void
|
|
15
17
|
}>()
|
|
16
18
|
|
|
17
19
|
defineComponentJson({
|
|
18
20
|
styleIsolation: 'apply-shared',
|
|
19
21
|
})
|
|
20
22
|
|
|
21
|
-
interface ActionItem {
|
|
22
|
-
key: string
|
|
23
|
-
title: string
|
|
24
|
-
description?: string
|
|
25
|
-
icon?: string
|
|
26
|
-
tag?: string
|
|
27
|
-
tone?: 'brand' | 'neutral'
|
|
28
|
-
disabled?: boolean
|
|
29
|
-
path?: string
|
|
30
|
-
type?: 'tab' | 'sub'
|
|
31
|
-
}
|
|
32
|
-
|
|
33
23
|
const cards = computed(() => (Array.isArray(props.items) ? props.items : []))
|
|
34
24
|
|
|
35
|
-
function onSelect(item:
|
|
25
|
+
function onSelect(item: QuickActionItem) {
|
|
36
26
|
if (item.disabled) {
|
|
37
27
|
return
|
|
38
28
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Dialog from 'tdesign-miniprogram/dialog/index'
|
|
2
|
+
import { getCurrentInstance } from 'wevu'
|
|
3
|
+
|
|
4
|
+
export interface DialogOptions {
|
|
5
|
+
selector?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface AlertOptions {
|
|
9
|
+
title: string
|
|
10
|
+
content: string
|
|
11
|
+
confirmBtn?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useDialog(options: DialogOptions = {}) {
|
|
15
|
+
const mpContext = getCurrentInstance()
|
|
16
|
+
const selector = options.selector ?? '#t-dialog'
|
|
17
|
+
|
|
18
|
+
function alert(payload: AlertOptions) {
|
|
19
|
+
if (!mpContext) {
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
Dialog.alert({
|
|
23
|
+
selector,
|
|
24
|
+
context: mpContext as any,
|
|
25
|
+
...payload,
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
alert,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ModelBindingOptions, ModelBindingPayload } from 'wevu'
|
|
2
|
+
import { useBindModel } from 'wevu'
|
|
3
|
+
|
|
4
|
+
export function useFormBinder() {
|
|
5
|
+
const bindModel = useBindModel()
|
|
6
|
+
|
|
7
|
+
function changeModel<T, ValueProp extends string = 'value', Formatted = T>(
|
|
8
|
+
path: string,
|
|
9
|
+
options?: ModelBindingOptions<T, 'change', ValueProp, Formatted>,
|
|
10
|
+
): ModelBindingPayload<T, 'change', ValueProp, Formatted> {
|
|
11
|
+
return bindModel(path).model({ event: 'change', ...options })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
changeModel,
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { onPullDownRefresh } from 'wevu'
|
|
2
|
+
|
|
3
|
+
export function usePullDownRefresh(refresh: () => void | Promise<void>) {
|
|
4
|
+
onPullDownRefresh(() => {
|
|
5
|
+
const result = refresh()
|
|
6
|
+
if (result && typeof (result as Promise<void>).catch === 'function') {
|
|
7
|
+
;(result as Promise<void>).catch(() => {})
|
|
8
|
+
}
|
|
9
|
+
wx.stopPullDownRefresh()
|
|
10
|
+
})
|
|
11
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Toast from 'tdesign-miniprogram/toast/index'
|
|
2
|
+
import { getCurrentInstance } from 'wevu'
|
|
3
|
+
|
|
4
|
+
export type ToastTheme = 'success' | 'warning' | 'error' | 'default' | 'loading'
|
|
5
|
+
|
|
6
|
+
export interface ToastOptions {
|
|
7
|
+
selector?: string
|
|
8
|
+
duration?: number
|
|
9
|
+
theme?: ToastTheme
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function useToast(options: ToastOptions = {}) {
|
|
13
|
+
const mpContext = getCurrentInstance()
|
|
14
|
+
const selector = options.selector ?? '#t-toast'
|
|
15
|
+
const duration = options.duration ?? 1200
|
|
16
|
+
const defaultTheme = options.theme ?? 'success'
|
|
17
|
+
|
|
18
|
+
function showToast(message: string, theme: ToastTheme = defaultTheme) {
|
|
19
|
+
if (!mpContext) {
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
Toast({
|
|
23
|
+
selector,
|
|
24
|
+
context: mpContext as any,
|
|
25
|
+
message,
|
|
26
|
+
theme,
|
|
27
|
+
duration,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
showToast,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import Toast from 'tdesign-miniprogram/toast/index'
|
|
4
|
-
|
|
5
|
-
import { getCurrentInstance, ref } from 'wevu'
|
|
2
|
+
import { ref } from 'wevu'
|
|
6
3
|
|
|
7
4
|
import SectionTitle from '@/components/SectionTitle/index.vue'
|
|
5
|
+
import { useDialog } from '@/hooks/useDialog'
|
|
6
|
+
import { useToast } from '@/hooks/useToast'
|
|
8
7
|
|
|
9
8
|
definePageJson({
|
|
10
9
|
navigationBarTitleText: '能力',
|
|
11
10
|
backgroundColor: '#f6f7fb',
|
|
12
11
|
})
|
|
13
12
|
|
|
14
|
-
const
|
|
13
|
+
const { alert } = useDialog()
|
|
14
|
+
const { showToast } = useToast()
|
|
15
15
|
|
|
16
16
|
const capabilityCards = ref([
|
|
17
17
|
{
|
|
@@ -43,19 +43,6 @@ const capabilityCards = ref([
|
|
|
43
43
|
|
|
44
44
|
const subscribeTemplateId = ''
|
|
45
45
|
|
|
46
|
-
function showToast(message: string, theme: 'success' | 'warning' = 'success') {
|
|
47
|
-
if (!mpContext) {
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
Toast({
|
|
51
|
-
selector: '#t-toast',
|
|
52
|
-
context: mpContext as any,
|
|
53
|
-
message,
|
|
54
|
-
theme,
|
|
55
|
-
duration: 1200,
|
|
56
|
-
})
|
|
57
|
-
}
|
|
58
|
-
|
|
59
46
|
function handleCapability(key: string) {
|
|
60
47
|
switch (key) {
|
|
61
48
|
case 'scan':
|
|
@@ -108,11 +95,9 @@ function handleCapability(key: string) {
|
|
|
108
95
|
|
|
109
96
|
function requestSubscribe() {
|
|
110
97
|
if (!subscribeTemplateId) {
|
|
111
|
-
|
|
112
|
-
selector: '#t-dialog',
|
|
98
|
+
alert({
|
|
113
99
|
title: '订阅消息',
|
|
114
100
|
content: '请在 ability 页面配置订阅模板 ID 后再试。',
|
|
115
|
-
context: mpContext as any,
|
|
116
101
|
confirmBtn: '知道了',
|
|
117
102
|
})
|
|
118
103
|
return
|
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { UploadFile } from 'tdesign-miniprogram/upload/type'
|
|
3
|
-
import type { ModelBindingOptions, ModelBindingPayload } from 'wevu'
|
|
4
|
-
import Toast from 'tdesign-miniprogram/toast/index'
|
|
5
3
|
|
|
6
|
-
import { computed,
|
|
4
|
+
import { computed, reactive, ref, watch } from 'wevu'
|
|
7
5
|
|
|
8
6
|
import FormRow from '@/components/FormRow/index.vue'
|
|
9
7
|
import FormStep from '@/components/FormStep/index.vue'
|
|
10
8
|
import ResultCard from '@/components/ResultCard/index.vue'
|
|
11
9
|
import SectionTitle from '@/components/SectionTitle/index.vue'
|
|
10
|
+
import { useFormBinder } from '@/hooks/useFormBinder'
|
|
11
|
+
import { useToast } from '@/hooks/useToast'
|
|
12
12
|
|
|
13
13
|
definePageJson({
|
|
14
14
|
navigationBarTitleText: '表单',
|
|
15
15
|
backgroundColor: '#f6f7fb',
|
|
16
16
|
})
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
function changeModel<T, ValueProp extends string = 'value', Formatted = T>(path: string, options?: ModelBindingOptions<T, 'change', ValueProp, Formatted>): ModelBindingPayload<T, 'change', ValueProp, Formatted> {
|
|
22
|
-
return bindModel(path).model({ event: 'change', ...options })
|
|
23
|
-
}
|
|
18
|
+
const { changeModel } = useFormBinder()
|
|
19
|
+
const { showToast } = useToast()
|
|
24
20
|
|
|
25
21
|
const steps = [
|
|
26
22
|
{ key: 'basic', title: '基础信息', subtitle: '业务基本配置' },
|
|
@@ -104,19 +100,6 @@ const attachmentsModel = changeModel<UploadFile[], 'files'>('formState.attachmen
|
|
|
104
100
|
parser: event => event?.detail?.files ?? [],
|
|
105
101
|
})
|
|
106
102
|
|
|
107
|
-
function showToast(message: string, theme: 'success' | 'warning' = 'success') {
|
|
108
|
-
if (!mpContext) {
|
|
109
|
-
return
|
|
110
|
-
}
|
|
111
|
-
Toast({
|
|
112
|
-
selector: '#t-toast',
|
|
113
|
-
context: mpContext as any,
|
|
114
|
-
message,
|
|
115
|
-
theme,
|
|
116
|
-
duration: 1200,
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
|
|
120
103
|
function goNext() {
|
|
121
104
|
if (!canGoNext.value) {
|
|
122
105
|
showToast('请先完善当前步骤信息', 'warning')
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import { computed, getCurrentInstance, onPullDownRefresh, ref, watch } from 'wevu'
|
|
2
|
+
import type { QuickActionItem } from '@/types/action'
|
|
5
3
|
|
|
4
|
+
import { computed, ref, watch } from 'wevu'
|
|
6
5
|
import KpiBoard from '@/components/KpiBoard/index.vue'
|
|
7
6
|
import QuickActionGrid from '@/components/QuickActionGrid/index.vue'
|
|
7
|
+
import { usePullDownRefresh } from '@/hooks/usePullDownRefresh'
|
|
8
|
+
import { useToast } from '@/hooks/useToast'
|
|
8
9
|
|
|
9
10
|
definePageJson({
|
|
10
11
|
navigationBarTitleText: '首页',
|
|
@@ -12,7 +13,7 @@ definePageJson({
|
|
|
12
13
|
backgroundColor: '#f6f7fb',
|
|
13
14
|
})
|
|
14
15
|
|
|
15
|
-
const
|
|
16
|
+
const { showToast } = useToast()
|
|
16
17
|
|
|
17
18
|
const noticeText = ref('欢迎体验 wevu + weapp-vite + TDesign 模板,已启用分包与多页面导航。')
|
|
18
19
|
const lastUpdated = ref('刚刚')
|
|
@@ -56,7 +57,7 @@ const kpiItems = computed(() => {
|
|
|
56
57
|
]
|
|
57
58
|
})
|
|
58
59
|
|
|
59
|
-
const quickActions = ref([
|
|
60
|
+
const quickActions = ref<QuickActionItem[]>([
|
|
60
61
|
{
|
|
61
62
|
key: 'data',
|
|
62
63
|
title: '数据洞察',
|
|
@@ -140,30 +141,14 @@ watch(refreshSeed, () => {
|
|
|
140
141
|
lastUpdated.value = `更新于 ${new Date().toLocaleTimeString()}`
|
|
141
142
|
})
|
|
142
143
|
|
|
143
|
-
|
|
144
|
-
refreshDashboard()
|
|
145
|
-
wx.stopPullDownRefresh()
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
function showToast(message: string) {
|
|
149
|
-
if (!mpContext) {
|
|
150
|
-
return
|
|
151
|
-
}
|
|
152
|
-
Toast({
|
|
153
|
-
selector: '#t-toast',
|
|
154
|
-
context: mpContext as any,
|
|
155
|
-
message,
|
|
156
|
-
theme: 'success',
|
|
157
|
-
duration: 1200,
|
|
158
|
-
})
|
|
159
|
-
}
|
|
144
|
+
usePullDownRefresh(refreshDashboard)
|
|
160
145
|
|
|
161
146
|
function refreshDashboard() {
|
|
162
147
|
refreshSeed.value = Math.max(1, Math.floor(Math.random() * 9))
|
|
163
148
|
showToast('指标已刷新')
|
|
164
149
|
}
|
|
165
150
|
|
|
166
|
-
function onQuickAction(action:
|
|
151
|
+
function onQuickAction(action: QuickActionItem) {
|
|
167
152
|
if (!action.path) {
|
|
168
153
|
showToast('该入口暂未配置')
|
|
169
154
|
return
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import { computed, getCurrentInstance, onPullDownRefresh, ref, watch } from 'wevu'
|
|
2
|
+
import type { ListItem, StatusFilter, StatusFilterValue } from '@/types/list'
|
|
5
3
|
|
|
4
|
+
import { computed, ref, watch } from 'wevu'
|
|
6
5
|
import EmptyState from '@/components/EmptyState/index.vue'
|
|
7
6
|
import FilterBar from '@/components/FilterBar/index.vue'
|
|
8
7
|
import SectionTitle from '@/components/SectionTitle/index.vue'
|
|
8
|
+
import { usePullDownRefresh } from '@/hooks/usePullDownRefresh'
|
|
9
|
+
import { useToast } from '@/hooks/useToast'
|
|
10
|
+
import { buildStatusFilters, filterListItems } from '@/utils/listFilters'
|
|
9
11
|
|
|
10
12
|
definePageJson({
|
|
11
13
|
navigationBarTitleText: '清单',
|
|
@@ -13,13 +15,13 @@ definePageJson({
|
|
|
13
15
|
enablePullDownRefresh: true,
|
|
14
16
|
})
|
|
15
17
|
|
|
16
|
-
const
|
|
18
|
+
const { showToast } = useToast({ duration: 1000 })
|
|
17
19
|
|
|
18
20
|
const query = ref('')
|
|
19
|
-
const activeStatus = ref('all')
|
|
21
|
+
const activeStatus = ref<StatusFilterValue>('all')
|
|
20
22
|
const loading = ref(true)
|
|
21
23
|
|
|
22
|
-
const items = ref([
|
|
24
|
+
const items = ref<ListItem[]>([
|
|
23
25
|
{
|
|
24
26
|
id: 1,
|
|
25
27
|
title: '门店会员激活方案',
|
|
@@ -54,50 +56,21 @@ const items = ref([
|
|
|
54
56
|
},
|
|
55
57
|
])
|
|
56
58
|
|
|
57
|
-
interface StatusFilter { value: string, label: string, count?: number }
|
|
58
|
-
|
|
59
59
|
const statusFilters = ref<StatusFilter[]>([])
|
|
60
60
|
|
|
61
61
|
function rebuildStatusFilters() {
|
|
62
|
-
|
|
63
|
-
const summary = source.reduce<Record<string, number>>((acc, item) => {
|
|
64
|
-
acc[item.status] = (acc[item.status] ?? 0) + 1
|
|
65
|
-
return acc
|
|
66
|
-
}, {})
|
|
67
|
-
statusFilters.value = [
|
|
68
|
-
{ value: 'all', label: '全部', count: source.length },
|
|
69
|
-
{ value: 'processing', label: '进行中', count: summary.processing ?? 0 },
|
|
70
|
-
{ value: 'pending', label: '待启动', count: summary.pending ?? 0 },
|
|
71
|
-
{ value: 'done', label: '已完成', count: summary.done ?? 0 },
|
|
72
|
-
]
|
|
62
|
+
statusFilters.value = buildStatusFilters(items.value)
|
|
73
63
|
}
|
|
74
64
|
|
|
75
65
|
rebuildStatusFilters()
|
|
76
66
|
watch(items, rebuildStatusFilters, { deep: true })
|
|
77
67
|
|
|
78
68
|
const filteredItems = computed(() =>
|
|
79
|
-
items.value.
|
|
80
|
-
const matchStatus = activeStatus.value === 'all' || item.status === activeStatus.value
|
|
81
|
-
const matchQuery = !query.value || item.title.includes(query.value) || item.owner.includes(query.value)
|
|
82
|
-
return matchStatus && matchQuery
|
|
83
|
-
}),
|
|
69
|
+
filterListItems(items.value, query.value, activeStatus.value),
|
|
84
70
|
)
|
|
85
71
|
|
|
86
72
|
const hasEmpty = computed(() => !loading.value && filteredItems.value.length === 0)
|
|
87
73
|
|
|
88
|
-
function showToast(message: string) {
|
|
89
|
-
if (!mpContext) {
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
Toast({
|
|
93
|
-
selector: '#t-toast',
|
|
94
|
-
context: mpContext as any,
|
|
95
|
-
message,
|
|
96
|
-
theme: 'success',
|
|
97
|
-
duration: 1000,
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
|
-
|
|
101
74
|
function reload() {
|
|
102
75
|
loading.value = true
|
|
103
76
|
setTimeout(() => {
|
|
@@ -110,10 +83,7 @@ function onAction(item: (typeof items.value)[number]) {
|
|
|
110
83
|
showToast(`打开「${item.title}」详情`)
|
|
111
84
|
}
|
|
112
85
|
|
|
113
|
-
|
|
114
|
-
reload()
|
|
115
|
-
wx.stopPullDownRefresh()
|
|
116
|
-
})
|
|
86
|
+
usePullDownRefresh(reload)
|
|
117
87
|
|
|
118
88
|
reload()
|
|
119
89
|
</script>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type ActionTone = 'brand' | 'neutral'
|
|
2
|
+
export type ActionType = 'tab' | 'sub'
|
|
3
|
+
|
|
4
|
+
export interface QuickActionItem {
|
|
5
|
+
key: string
|
|
6
|
+
title: string
|
|
7
|
+
description?: string
|
|
8
|
+
icon?: string
|
|
9
|
+
tag?: string
|
|
10
|
+
tone?: ActionTone
|
|
11
|
+
disabled?: boolean
|
|
12
|
+
path?: string
|
|
13
|
+
type?: ActionType
|
|
14
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ListStatus = 'processing' | 'pending' | 'done'
|
|
2
|
+
export type StatusFilterValue = 'all' | ListStatus
|
|
3
|
+
|
|
4
|
+
export interface ListItem {
|
|
5
|
+
id: number
|
|
6
|
+
title: string
|
|
7
|
+
owner: string
|
|
8
|
+
status: ListStatus
|
|
9
|
+
deadline: string
|
|
10
|
+
priority: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface StatusFilter {
|
|
14
|
+
value: StatusFilterValue
|
|
15
|
+
label: string
|
|
16
|
+
count?: number
|
|
17
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ListItem, ListStatus, StatusFilter, StatusFilterValue } from '@/types/list'
|
|
2
|
+
|
|
3
|
+
export function buildStatusFilters(items: ListItem[]): StatusFilter[] {
|
|
4
|
+
const summary: Record<ListStatus, number> = {
|
|
5
|
+
processing: 0,
|
|
6
|
+
pending: 0,
|
|
7
|
+
done: 0,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
for (const item of items) {
|
|
11
|
+
summary[item.status] += 1
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return [
|
|
15
|
+
{ value: 'all', label: '全部', count: items.length },
|
|
16
|
+
{ value: 'processing', label: '进行中', count: summary.processing },
|
|
17
|
+
{ value: 'pending', label: '待启动', count: summary.pending },
|
|
18
|
+
{ value: 'done', label: '已完成', count: summary.done },
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function filterListItems(
|
|
23
|
+
items: ListItem[],
|
|
24
|
+
query: string,
|
|
25
|
+
activeStatus: StatusFilterValue,
|
|
26
|
+
) {
|
|
27
|
+
const keyword = query.trim()
|
|
28
|
+
|
|
29
|
+
return items.filter((item) => {
|
|
30
|
+
const matchStatus = activeStatus === 'all' || item.status === activeStatus
|
|
31
|
+
const matchQuery = !keyword || item.title.includes(keyword) || item.owner.includes(keyword)
|
|
32
|
+
return matchStatus && matchQuery
|
|
33
|
+
})
|
|
34
|
+
}
|