create-weapp-vite 2.0.4 → 2.0.5

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-weapp-vite",
3
3
  "type": "module",
4
- "version": "2.0.4",
4
+ "version": "2.0.5",
5
5
  "description": "create-weapp-vite",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -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?: ActionItem[]
9
+ items?: QuickActionItem[]
8
10
  }>(), {
9
11
  subtitle: '',
10
12
  items: () => [],
11
13
  })
12
14
 
13
15
  const emit = defineEmits<{
14
- (e: 'select', item: ActionItem): void
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: ActionItem) {
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 Dialog from 'tdesign-miniprogram/dialog/index'
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 mpContext = getCurrentInstance()
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
- Dialog.alert({
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, getCurrentInstance, reactive, ref, useBindModel, watch } from 'wevu'
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 mpContext = getCurrentInstance()
19
- const bindModel = useBindModel()
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 Toast from 'tdesign-miniprogram/toast/index'
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 mpContext = getCurrentInstance()
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
- onPullDownRefresh(() => {
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: { path?: string, type?: 'tab' | 'sub', title: string }) {
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 Toast from 'tdesign-miniprogram/toast/index'
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 mpContext = getCurrentInstance()
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
- const source = Array.isArray(items.value) ? items.value : []
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.filter((item) => {
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
- onPullDownRefresh(() => {
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
+ }