create-weapp-vite 2.3.15 → 2.3.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/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-D8uqfCKh.js → src-C8kzMXK7.js} +1 -1
- package/package.json +1 -1
- package/templates/wevu/README.md +3 -3
- package/templates/wevu/package.json +1 -1
- package/templates/wevu/src/app.vue +1 -60
- package/templates/wevu/src/pages/index/index.vue +26 -194
- package/templates/wevu/src/pages/layouts/index.vue +0 -18
- package/templates/wevu/weapp-vite.config.ts +0 -7
- package/templates/wevu-tdesign/README.md +3 -6
- package/templates/wevu-tdesign/package.json +1 -1
- package/templates/wevu-tdesign/project.private.config.json +0 -66
- package/templates/wevu-tdesign/src/app.vue +1 -73
- package/templates/wevu-tdesign/src/pages/index/index.vue +19 -362
- package/templates/wevu/src/components/InfoPanel/index.vue +0 -52
- package/templates/wevu/src/components/StatusPill/index.vue +0 -42
- package/templates/wevu/src/packageA/pages/workspace/index.vue +0 -137
- package/templates/wevu/src/packageB/pages/settings/index.vue +0 -131
- package/templates/wevu/src/pages/overview/index.vue +0 -149
- package/templates/wevu-tdesign/public/tabbar/ability-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/ability.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/data-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/data.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/form-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/form.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/home-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/home.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/list-active.png +0 -0
- package/templates/wevu-tdesign/public/tabbar/list.png +0 -0
- package/templates/wevu-tdesign/src/components/EmptyState/index.vue +0 -36
- package/templates/wevu-tdesign/src/components/FilterBar/index.vue +0 -64
- package/templates/wevu-tdesign/src/components/FormRow/index.vue +0 -43
- package/templates/wevu-tdesign/src/components/FormStep/index.vue +0 -48
- package/templates/wevu-tdesign/src/components/KpiBoard/index.vue +0 -145
- package/templates/wevu-tdesign/src/components/QuickActionGrid/index.vue +0 -79
- package/templates/wevu-tdesign/src/components/ResultCard/index.vue +0 -51
- package/templates/wevu-tdesign/src/components/SectionTitle/index.vue +0 -34
- package/templates/wevu-tdesign/src/components/TrendCard/index.vue +0 -101
- package/templates/wevu-tdesign/src/components/VirtualHostClassDemo/BrokenCard.vue +0 -46
- package/templates/wevu-tdesign/src/components/VirtualHostClassDemo/FixedExternalClassCard.vue +0 -50
- package/templates/wevu-tdesign/src/components/VirtualHostClassDemo/RecommendedCard.vue +0 -53
- package/templates/wevu-tdesign/src/hooks/useDialog.ts +0 -205
- package/templates/wevu-tdesign/src/hooks/useFormBinder.ts +0 -17
- package/templates/wevu-tdesign/src/hooks/useLayoutFeedbackBridge.ts +0 -17
- package/templates/wevu-tdesign/src/hooks/usePullDownRefresh.ts +0 -12
- package/templates/wevu-tdesign/src/hooks/useToast.ts +0 -100
- package/templates/wevu-tdesign/src/layouts/admin.vue +0 -41
- package/templates/wevu-tdesign/src/layouts/default.vue +0 -23
- package/templates/wevu-tdesign/src/pages/ability/index.vue +0 -164
- package/templates/wevu-tdesign/src/pages/data/index.vue +0 -189
- package/templates/wevu-tdesign/src/pages/form/index.vue +0 -271
- package/templates/wevu-tdesign/src/pages/layout-feedback/components/FeedbackCallerCard.vue +0 -79
- package/templates/wevu-tdesign/src/pages/layout-feedback/index.vue +0 -211
- package/templates/wevu-tdesign/src/pages/layout-store/index.vue +0 -127
- package/templates/wevu-tdesign/src/pages/layouts/index.vue +0 -120
- package/templates/wevu-tdesign/src/pages/list/index.vue +0 -146
- package/templates/wevu-tdesign/src/stores/layoutInteractionDemo.ts +0 -129
- package/templates/wevu-tdesign/src/subpackages/ability/index.vue +0 -103
- package/templates/wevu-tdesign/src/subpackages/lab/class-binding/index.vue +0 -440
- package/templates/wevu-tdesign/src/subpackages/lab/index.vue +0 -169
- package/templates/wevu-tdesign/src/subpackages/lab/virtual-host-class/index.vue +0 -94
- package/templates/wevu-tdesign/src/types/action.ts +0 -14
- package/templates/wevu-tdesign/src/types/list.ts +0 -17
- package/templates/wevu-tdesign/src/utils/changeEvent.ts +0 -53
- package/templates/wevu-tdesign/src/utils/listFilters.ts +0 -34
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'wevu'
|
|
3
|
-
import { useRoute, useRouter } from 'wevu/router'
|
|
4
|
-
|
|
5
|
-
definePageJson({
|
|
6
|
-
navigationBarTitleText: '系统设置',
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
const HOME_PATH = '/pages/index/index'
|
|
10
|
-
const OVERVIEW_PATH = '/pages/overview/index'
|
|
11
|
-
|
|
12
|
-
const route = useRoute()
|
|
13
|
-
const router = useRouter()
|
|
14
|
-
|
|
15
|
-
const routeSummary = computed(() => route.fullPath || `/${route.path}`)
|
|
16
|
-
|
|
17
|
-
const settingGroups = [
|
|
18
|
-
{
|
|
19
|
-
title: '通知策略',
|
|
20
|
-
description: '预留站内消息、邮件提醒和审批通知等配置位置。',
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
title: '角色权限',
|
|
24
|
-
description: '适合接入组织结构、角色分级与操作授权等业务能力。',
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
title: '环境信息',
|
|
28
|
-
description: '可以继续扩展版本号、发布通道和系统参数等正式模块。',
|
|
29
|
-
},
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
async function relaunchHome() {
|
|
33
|
-
await router.nativeRouter.reLaunch({
|
|
34
|
-
url: HOME_PATH,
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
</script>
|
|
38
|
-
|
|
39
|
-
<template>
|
|
40
|
-
<view class="page">
|
|
41
|
-
<view class="card">
|
|
42
|
-
<view class="card__eyebrow">
|
|
43
|
-
Settings
|
|
44
|
-
</view>
|
|
45
|
-
<view class="card__title">
|
|
46
|
-
系统设置
|
|
47
|
-
</view>
|
|
48
|
-
<view class="card__desc">
|
|
49
|
-
独立分包适合作为设置、配置或低频但相对独立的业务模块承载区。
|
|
50
|
-
</view>
|
|
51
|
-
<view class="card__summary">
|
|
52
|
-
当前路由:{{ routeSummary }}
|
|
53
|
-
</view>
|
|
54
|
-
</view>
|
|
55
|
-
|
|
56
|
-
<view
|
|
57
|
-
v-for="item in settingGroups"
|
|
58
|
-
:key="item.title"
|
|
59
|
-
class="panel-wrap"
|
|
60
|
-
>
|
|
61
|
-
<InfoPanel
|
|
62
|
-
eyebrow="SETTING"
|
|
63
|
-
:title="item.title"
|
|
64
|
-
:description="item.description"
|
|
65
|
-
/>
|
|
66
|
-
</view>
|
|
67
|
-
|
|
68
|
-
<button class="action-btn" @tap="router.push(OVERVIEW_PATH)">
|
|
69
|
-
查看运营概览
|
|
70
|
-
</button>
|
|
71
|
-
<button class="action-btn action-btn--ghost" @tap="relaunchHome">
|
|
72
|
-
reLaunch 回业务门户
|
|
73
|
-
</button>
|
|
74
|
-
</view>
|
|
75
|
-
</template>
|
|
76
|
-
|
|
77
|
-
<style>
|
|
78
|
-
.page {
|
|
79
|
-
box-sizing: border-box;
|
|
80
|
-
min-height: 100vh;
|
|
81
|
-
padding: 34rpx 30rpx;
|
|
82
|
-
background:
|
|
83
|
-
radial-gradient(circle at top left, rgb(148 163 184 / 14%), transparent 26%),
|
|
84
|
-
linear-gradient(180deg, #f8fafc 0%, #eef2f6 100%);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.card {
|
|
88
|
-
padding: 30rpx 28rpx;
|
|
89
|
-
background: #fff;
|
|
90
|
-
border: 2rpx solid #cbd5e1;
|
|
91
|
-
border-radius: 30rpx;
|
|
92
|
-
box-shadow: 0 16rpx 36rpx rgb(15 23 42 / 5%);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.card__eyebrow {
|
|
96
|
-
font-size: 22rpx;
|
|
97
|
-
font-weight: 600;
|
|
98
|
-
color: #475569;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.card__title {
|
|
102
|
-
margin-top: 10rpx;
|
|
103
|
-
font-size: 40rpx;
|
|
104
|
-
font-weight: 700;
|
|
105
|
-
color: #0f172a;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.card__desc,
|
|
109
|
-
.card__summary {
|
|
110
|
-
margin-top: 12rpx;
|
|
111
|
-
font-size: 24rpx;
|
|
112
|
-
line-height: 1.6;
|
|
113
|
-
color: #475569;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.panel-wrap {
|
|
117
|
-
margin-top: 18rpx;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.action-btn {
|
|
121
|
-
margin-top: 18rpx;
|
|
122
|
-
color: #fff;
|
|
123
|
-
background: #0f172a;
|
|
124
|
-
border-radius: 999rpx;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.action-btn--ghost {
|
|
128
|
-
color: #0f172a;
|
|
129
|
-
background: #e2e8f0;
|
|
130
|
-
}
|
|
131
|
-
</style>
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'wevu'
|
|
3
|
-
import { useRoute, useRouter } from 'wevu/router'
|
|
4
|
-
|
|
5
|
-
definePageJson({
|
|
6
|
-
navigationBarTitleText: '运营概览',
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
const HOME_PATH = '/pages/index/index'
|
|
10
|
-
const WORKSPACE_PATH = '/packageA/pages/workspace/index'
|
|
11
|
-
const SETTINGS_PATH = '/packageB/pages/settings/index'
|
|
12
|
-
|
|
13
|
-
const route = useRoute()
|
|
14
|
-
const router = useRouter()
|
|
15
|
-
|
|
16
|
-
const summary = computed(() => {
|
|
17
|
-
return route.fullPath || `/${route.path}`
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const focusItems = [
|
|
21
|
-
{
|
|
22
|
-
title: '项目节奏稳定',
|
|
23
|
-
description: '需求冻结、设计评审与联调时间线已经对齐,适合继续扩展到实际业务场景。',
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
title: '协作角色清晰',
|
|
27
|
-
description: '可在此基础上继续接入团队成员、审批流或项目动态等正式模块。',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
title: '模板结构简洁',
|
|
31
|
-
description: '页面布局保留必要层级,既能做展示页,也能平滑承接后台工作流。',
|
|
32
|
-
},
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
async function toSettings() {
|
|
36
|
-
await router.push(SETTINGS_PATH)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function backHome() {
|
|
40
|
-
await router.push(HOME_PATH)
|
|
41
|
-
}
|
|
42
|
-
</script>
|
|
43
|
-
|
|
44
|
-
<template>
|
|
45
|
-
<view class="page">
|
|
46
|
-
<view class="card">
|
|
47
|
-
<view class="card__eyebrow">
|
|
48
|
-
Overview
|
|
49
|
-
</view>
|
|
50
|
-
<view class="card__title">
|
|
51
|
-
运营概览
|
|
52
|
-
</view>
|
|
53
|
-
<view class="card__desc">
|
|
54
|
-
用正式模板的方式承载项目状态、团队节奏和阶段重点,而不是单纯展示路由跳转能力。
|
|
55
|
-
</view>
|
|
56
|
-
<view class="card__summary">
|
|
57
|
-
当前路由:{{ summary }}
|
|
58
|
-
</view>
|
|
59
|
-
</view>
|
|
60
|
-
|
|
61
|
-
<view
|
|
62
|
-
v-for="item in focusItems"
|
|
63
|
-
:key="item.title"
|
|
64
|
-
class="panel-wrap"
|
|
65
|
-
>
|
|
66
|
-
<InfoPanel
|
|
67
|
-
eyebrow="FOCUS"
|
|
68
|
-
:title="item.title"
|
|
69
|
-
:description="item.description"
|
|
70
|
-
/>
|
|
71
|
-
</view>
|
|
72
|
-
|
|
73
|
-
<view class="actions">
|
|
74
|
-
<button class="action-btn" @tap="router.push(WORKSPACE_PATH)">
|
|
75
|
-
进入项目工作台
|
|
76
|
-
</button>
|
|
77
|
-
<button class="action-btn action-btn--secondary" @tap="toSettings">
|
|
78
|
-
查看系统设置
|
|
79
|
-
</button>
|
|
80
|
-
<button class="action-btn action-btn--ghost" @tap="backHome">
|
|
81
|
-
返回业务门户
|
|
82
|
-
</button>
|
|
83
|
-
</view>
|
|
84
|
-
</view>
|
|
85
|
-
</template>
|
|
86
|
-
|
|
87
|
-
<style>
|
|
88
|
-
.page {
|
|
89
|
-
box-sizing: border-box;
|
|
90
|
-
min-height: 100vh;
|
|
91
|
-
padding: 30rpx;
|
|
92
|
-
background:
|
|
93
|
-
radial-gradient(circle at top left, rgb(16 185 129 / 10%), transparent 28%),
|
|
94
|
-
linear-gradient(180deg, #f6fbf8 0%, #edf5f1 100%);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.card {
|
|
98
|
-
padding: 32rpx 28rpx;
|
|
99
|
-
background: #fff;
|
|
100
|
-
border: 2rpx solid #d1fae5;
|
|
101
|
-
border-radius: 30rpx;
|
|
102
|
-
box-shadow: 0 16rpx 36rpx rgb(15 23 42 / 5%);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.card__eyebrow {
|
|
106
|
-
font-size: 22rpx;
|
|
107
|
-
font-weight: 600;
|
|
108
|
-
color: #0f766e;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.card__title {
|
|
112
|
-
margin-top: 10rpx;
|
|
113
|
-
font-size: 40rpx;
|
|
114
|
-
font-weight: 700;
|
|
115
|
-
color: #134e4a;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.card__desc,
|
|
119
|
-
.card__summary {
|
|
120
|
-
margin-top: 12rpx;
|
|
121
|
-
font-size: 24rpx;
|
|
122
|
-
line-height: 1.6;
|
|
123
|
-
color: #335c58;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.panel-wrap {
|
|
127
|
-
margin-top: 18rpx;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.actions {
|
|
131
|
-
margin-top: 10rpx;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.action-btn {
|
|
135
|
-
margin-top: 18rpx;
|
|
136
|
-
color: #fff;
|
|
137
|
-
background: #0f766e;
|
|
138
|
-
border-radius: 999rpx;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.action-btn--secondary {
|
|
142
|
-
background: #1d4ed8;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.action-btn--ghost {
|
|
146
|
-
color: #134e4a;
|
|
147
|
-
background: #d1fae5;
|
|
148
|
-
}
|
|
149
|
-
</style>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const props = withDefaults(
|
|
3
|
-
defineProps<{
|
|
4
|
-
title: string
|
|
5
|
-
description?: string
|
|
6
|
-
actionText?: string
|
|
7
|
-
}>(),
|
|
8
|
-
{
|
|
9
|
-
description: '',
|
|
10
|
-
actionText: '',
|
|
11
|
-
},
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
const emit = defineEmits<{
|
|
15
|
-
(e: 'action'): void
|
|
16
|
-
}>()
|
|
17
|
-
|
|
18
|
-
defineComponentJson({
|
|
19
|
-
styleIsolation: 'apply-shared',
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
function onAction() {
|
|
23
|
-
emit('action')
|
|
24
|
-
}
|
|
25
|
-
</script>
|
|
26
|
-
|
|
27
|
-
<template>
|
|
28
|
-
<view class="rounded-[20rpx] bg-white p-[24rpx] shadow-[0_12rpx_28rpx_rgba(17,24,39,0.08)]">
|
|
29
|
-
<t-empty :title="title" :description="description" />
|
|
30
|
-
<view v-if="props.actionText" class="mt-[16rpx]">
|
|
31
|
-
<t-button block theme="primary" variant="outline" @tap="onAction">
|
|
32
|
-
{{ props.actionText }}
|
|
33
|
-
</t-button>
|
|
34
|
-
</view>
|
|
35
|
-
</view>
|
|
36
|
-
</template>
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'wevu'
|
|
3
|
-
import { resolveStringChangeValue } from '@/utils/changeEvent'
|
|
4
|
-
|
|
5
|
-
const props = withDefaults(defineProps<{
|
|
6
|
-
query?: string
|
|
7
|
-
active?: string
|
|
8
|
-
filters?: FilterItem[]
|
|
9
|
-
}>(), {
|
|
10
|
-
query: '',
|
|
11
|
-
active: 'all',
|
|
12
|
-
filters: () => [],
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
const emit = defineEmits<{
|
|
16
|
-
(e: 'update:query', value: string): void
|
|
17
|
-
(e: 'update:active', value: string): void
|
|
18
|
-
}>()
|
|
19
|
-
|
|
20
|
-
defineComponentJson({
|
|
21
|
-
styleIsolation: 'apply-shared',
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
interface FilterItem {
|
|
25
|
-
value: string
|
|
26
|
-
label: string
|
|
27
|
-
count?: number
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const filterItems = computed(() => (Array.isArray(props.filters) ? props.filters : []))
|
|
31
|
-
|
|
32
|
-
function onQueryChange(event: unknown) {
|
|
33
|
-
emit('update:query', resolveStringChangeValue(event, props.query))
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function onSelect(value: string) {
|
|
37
|
-
emit('update:active', value)
|
|
38
|
-
}
|
|
39
|
-
</script>
|
|
40
|
-
|
|
41
|
-
<template>
|
|
42
|
-
<view class="rounded-[20rpx] bg-white p-[16rpx] shadow-[0_12rpx_28rpx_rgba(17,24,39,0.08)]">
|
|
43
|
-
<t-search
|
|
44
|
-
placeholder="搜索标题或负责人"
|
|
45
|
-
:value="query"
|
|
46
|
-
clearable
|
|
47
|
-
@change="onQueryChange"
|
|
48
|
-
/>
|
|
49
|
-
<view class="mt-[12rpx] flex flex-wrap gap-[12rpx]">
|
|
50
|
-
<t-check-tag
|
|
51
|
-
v-for="item in filterItems"
|
|
52
|
-
:key="item.value"
|
|
53
|
-
:checked="item.value === active"
|
|
54
|
-
content=""
|
|
55
|
-
@change="onSelect(item.value)"
|
|
56
|
-
>
|
|
57
|
-
{{ item.label }}
|
|
58
|
-
<text v-if="item.count !== undefined">
|
|
59
|
-
({{ item.count }})
|
|
60
|
-
</text>
|
|
61
|
-
</t-check-tag>
|
|
62
|
-
</view>
|
|
63
|
-
</view>
|
|
64
|
-
</template>
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'wevu'
|
|
3
|
-
|
|
4
|
-
const props = withDefaults(
|
|
5
|
-
defineProps<{
|
|
6
|
-
label: string
|
|
7
|
-
align?: 'left' | 'center' | 'right'
|
|
8
|
-
description?: string
|
|
9
|
-
}>(),
|
|
10
|
-
{
|
|
11
|
-
align: 'left',
|
|
12
|
-
description: '',
|
|
13
|
-
},
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
defineComponentJson({
|
|
17
|
-
styleIsolation: 'apply-shared',
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const labelClass = computed(() => {
|
|
21
|
-
if (props.align === 'right') {
|
|
22
|
-
return 'text-right'
|
|
23
|
-
}
|
|
24
|
-
if (props.align === 'center') {
|
|
25
|
-
return 'text-center'
|
|
26
|
-
}
|
|
27
|
-
return 'text-left'
|
|
28
|
-
})
|
|
29
|
-
</script>
|
|
30
|
-
|
|
31
|
-
<template>
|
|
32
|
-
<view class="flex flex-col gap-[8rpx]">
|
|
33
|
-
<view class="flex items-baseline justify-between gap-[12rpx]">
|
|
34
|
-
<text class="text-[22rpx] font-semibold text-[#1f1a3f]" :class="labelClass">
|
|
35
|
-
{{ label }}
|
|
36
|
-
</text>
|
|
37
|
-
<text v-if="description" class="text-[20rpx] text-[#8a8aa5]">
|
|
38
|
-
{{ description }}
|
|
39
|
-
</text>
|
|
40
|
-
</view>
|
|
41
|
-
<slot />
|
|
42
|
-
</view>
|
|
43
|
-
</template>
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
defineOptions({
|
|
3
|
-
options: {
|
|
4
|
-
multipleSlots: true,
|
|
5
|
-
},
|
|
6
|
-
})
|
|
7
|
-
|
|
8
|
-
withDefaults(
|
|
9
|
-
defineProps<{
|
|
10
|
-
step: number
|
|
11
|
-
title: string
|
|
12
|
-
subtitle?: string
|
|
13
|
-
active?: boolean
|
|
14
|
-
}>(),
|
|
15
|
-
{
|
|
16
|
-
subtitle: '',
|
|
17
|
-
active: false,
|
|
18
|
-
},
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
defineComponentJson({
|
|
22
|
-
styleIsolation: 'apply-shared',
|
|
23
|
-
})
|
|
24
|
-
</script>
|
|
25
|
-
|
|
26
|
-
<template>
|
|
27
|
-
<view class="rounded-[20rpx] bg-white p-[20rpx] shadow-[0_12rpx_28rpx_rgba(17,24,39,0.08)]">
|
|
28
|
-
<view class="flex items-center gap-[12rpx]">
|
|
29
|
-
<view
|
|
30
|
-
class="flex h-[36rpx] w-[36rpx] items-center justify-center rounded-full text-[20rpx] font-semibold"
|
|
31
|
-
:class="active ? 'bg-[#2f2b5f] text-white' : 'bg-[#eff1f6] text-[#5c5b7a]'"
|
|
32
|
-
>
|
|
33
|
-
{{ step }}
|
|
34
|
-
</view>
|
|
35
|
-
<view>
|
|
36
|
-
<text class="text-[26rpx] font-semibold text-[#1f1a3f]">
|
|
37
|
-
{{ title }}
|
|
38
|
-
</text>
|
|
39
|
-
<text v-if="subtitle" class="mt-[4rpx] block text-[20rpx] text-[#6f6b8a]">
|
|
40
|
-
{{ subtitle }}
|
|
41
|
-
</text>
|
|
42
|
-
</view>
|
|
43
|
-
</view>
|
|
44
|
-
<view class="mt-[16rpx]">
|
|
45
|
-
<slot />
|
|
46
|
-
</view>
|
|
47
|
-
</view>
|
|
48
|
-
</template>
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'wevu'
|
|
3
|
-
|
|
4
|
-
defineOptions({
|
|
5
|
-
options: {
|
|
6
|
-
multipleSlots: true,
|
|
7
|
-
},
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
const props = withDefaults(defineProps<{
|
|
11
|
-
title: string
|
|
12
|
-
subtitle?: string
|
|
13
|
-
items?: KpiItem[]
|
|
14
|
-
columns?: 2 | 3
|
|
15
|
-
}>(), {
|
|
16
|
-
subtitle: '',
|
|
17
|
-
items: () => [],
|
|
18
|
-
columns: 2,
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
type KpiTone = 'positive' | 'negative' | 'neutral'
|
|
22
|
-
|
|
23
|
-
export interface KpiItem {
|
|
24
|
-
key?: string
|
|
25
|
-
label: string
|
|
26
|
-
value: string | number
|
|
27
|
-
unit?: string
|
|
28
|
-
delta?: number
|
|
29
|
-
footnote?: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
defineComponentJson({
|
|
33
|
-
styleIsolation: 'apply-shared',
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
function resolveTone(delta?: number): KpiTone {
|
|
37
|
-
if (delta === undefined || Number.isNaN(delta)) {
|
|
38
|
-
return 'neutral'
|
|
39
|
-
}
|
|
40
|
-
if (delta > 0) {
|
|
41
|
-
return 'positive'
|
|
42
|
-
}
|
|
43
|
-
if (delta < 0) {
|
|
44
|
-
return 'negative'
|
|
45
|
-
}
|
|
46
|
-
return 'neutral'
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const cards = computed(() => {
|
|
50
|
-
const source = Array.isArray(props.items) ? props.items : []
|
|
51
|
-
return source.map((item, index) => ({
|
|
52
|
-
key: item.key ?? String(index),
|
|
53
|
-
item,
|
|
54
|
-
index,
|
|
55
|
-
tone: resolveTone(item.delta),
|
|
56
|
-
isLeading: index === 0,
|
|
57
|
-
}))
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
const gridClass = computed(() => (props.columns === 3 ? 'grid-cols-3' : 'grid-cols-2'))
|
|
61
|
-
|
|
62
|
-
function formatDelta(delta?: number, unit = '') {
|
|
63
|
-
if (delta === undefined || Number.isNaN(delta)) {
|
|
64
|
-
return '--'
|
|
65
|
-
}
|
|
66
|
-
const sign = delta > 0 ? '+' : ''
|
|
67
|
-
return `${sign}${delta}${unit}`
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function toneBadgeClass(tone: KpiTone) {
|
|
71
|
-
if (tone === 'positive') {
|
|
72
|
-
return 'bg-[#e7f7ee] text-[#1b7a3a]'
|
|
73
|
-
}
|
|
74
|
-
if (tone === 'negative') {
|
|
75
|
-
return 'bg-[#ffe9e9] text-[#b42318]'
|
|
76
|
-
}
|
|
77
|
-
return 'bg-[#edf1f7] text-[#64748b]'
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function toneDotClass(tone: KpiTone) {
|
|
81
|
-
if (tone === 'positive') {
|
|
82
|
-
return 'bg-[#22c55e]'
|
|
83
|
-
}
|
|
84
|
-
if (tone === 'negative') {
|
|
85
|
-
return 'bg-[#ef4444]'
|
|
86
|
-
}
|
|
87
|
-
return 'bg-[#94a3b8]'
|
|
88
|
-
}
|
|
89
|
-
</script>
|
|
90
|
-
|
|
91
|
-
<template>
|
|
92
|
-
<view class="rounded-[24rpx] bg-white p-[20rpx] shadow-[0_18rpx_40rpx_rgba(17,24,39,0.08)]">
|
|
93
|
-
<view class="flex items-end justify-between">
|
|
94
|
-
<view>
|
|
95
|
-
<text class="text-[28rpx] font-semibold text-[#1f1a3f]">
|
|
96
|
-
{{ title }}
|
|
97
|
-
</text>
|
|
98
|
-
<text v-if="subtitle" class="mt-[6rpx] block text-[22rpx] text-[#6f6b8a]">
|
|
99
|
-
{{ subtitle }}
|
|
100
|
-
</text>
|
|
101
|
-
</view>
|
|
102
|
-
<slot name="action" />
|
|
103
|
-
</view>
|
|
104
|
-
<view class="mt-[16rpx] grid gap-[12rpx]" :class="gridClass">
|
|
105
|
-
<slot name="items" :items="cards">
|
|
106
|
-
<view v-for="card in cards" :key="card.key">
|
|
107
|
-
<view class="rounded-[18rpx] bg-[#f7f7fb] p-[16rpx]">
|
|
108
|
-
<view class="flex items-center justify-between">
|
|
109
|
-
<view class="flex items-center gap-[8rpx]">
|
|
110
|
-
<view class="h-[8rpx] w-[8rpx] rounded-full" :class="toneDotClass(card.tone)" />
|
|
111
|
-
<text class="text-[22rpx] text-[#61618a]">
|
|
112
|
-
{{ card.item.label }}
|
|
113
|
-
</text>
|
|
114
|
-
</view>
|
|
115
|
-
<view v-if="card.isLeading" class="rounded-full bg-[#fff3c2] px-[10rpx] py-[4rpx]">
|
|
116
|
-
<text class="text-[18rpx] font-semibold text-[#8a5200]">
|
|
117
|
-
HOT
|
|
118
|
-
</text>
|
|
119
|
-
</view>
|
|
120
|
-
</view>
|
|
121
|
-
<view class="mt-[10rpx] flex items-end justify-between">
|
|
122
|
-
<view class="flex items-baseline gap-[6rpx]">
|
|
123
|
-
<text class="text-[32rpx] font-bold text-[#1c1c3c]">
|
|
124
|
-
{{ card.item.value }}
|
|
125
|
-
</text>
|
|
126
|
-
<text v-if="card.item.unit" class="text-[20rpx] text-[#7a7aa0]">
|
|
127
|
-
{{ card.item.unit }}
|
|
128
|
-
</text>
|
|
129
|
-
</view>
|
|
130
|
-
<view class="rounded-full px-[10rpx] py-[4rpx]" :class="toneBadgeClass(card.tone)">
|
|
131
|
-
<text class="text-[20rpx] font-semibold">
|
|
132
|
-
{{ card.tone === 'positive' ? '↑' : card.tone === 'negative' ? '↓' : '→' }}
|
|
133
|
-
{{ formatDelta(card.item.delta, card.item.unit ?? '') }}
|
|
134
|
-
</text>
|
|
135
|
-
</view>
|
|
136
|
-
</view>
|
|
137
|
-
<text v-if="card.item.footnote" class="mt-[6rpx] block text-[20rpx] text-[#8a8aa5]">
|
|
138
|
-
{{ card.item.footnote }}
|
|
139
|
-
</text>
|
|
140
|
-
</view>
|
|
141
|
-
</view>
|
|
142
|
-
</slot>
|
|
143
|
-
</view>
|
|
144
|
-
</view>
|
|
145
|
-
</template>
|