@morya-ui/mcp 0.2.7 → 0.2.9
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/README.md +1 -1
- package/data/catalog.json +448 -96
- package/data/example-coverage.json +40 -5
- package/data/golden-pages/dashboard-page.vue +41 -8
- package/data/golden-pages/empty-state.vue +22 -1
- package/data/golden-pages/form-page.vue +1 -1
- package/data/golden-pages/landing-page.vue +31 -1
- package/data/golden-pages/list-page.vue +25 -12
- package/data/golden-pages/login-page.vue +44 -4
- package/dist/__tests__/tools.test.js +10 -0
- package/dist/decisions.js +205 -1
- package/dist/page-snippets.js +27 -17
- package/dist/patterns.d.ts +4 -2
- package/dist/patterns.js +11 -9
- package/dist/tools.js +25 -5
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-09-
|
|
3
|
-
"catalogGeneratedAt": "2026-09-
|
|
2
|
+
"generatedAt": "2026-09-21T09:57:51.741Z",
|
|
3
|
+
"catalogGeneratedAt": "2026-09-21T09:57:47.817Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
6
6
|
"id": "Accordion",
|
|
@@ -1604,6 +1604,41 @@
|
|
|
1604
1604
|
"missing": []
|
|
1605
1605
|
}
|
|
1606
1606
|
},
|
|
1607
|
+
{
|
|
1608
|
+
"id": "Loading",
|
|
1609
|
+
"exportName": "MLoading",
|
|
1610
|
+
"examples": 14,
|
|
1611
|
+
"props": {
|
|
1612
|
+
"total": 11,
|
|
1613
|
+
"covered": 4,
|
|
1614
|
+
"missing": [
|
|
1615
|
+
"ariaLabel",
|
|
1616
|
+
"background",
|
|
1617
|
+
"customClass",
|
|
1618
|
+
"fullscreen",
|
|
1619
|
+
"lock",
|
|
1620
|
+
"delay",
|
|
1621
|
+
"pt"
|
|
1622
|
+
]
|
|
1623
|
+
},
|
|
1624
|
+
"events": {
|
|
1625
|
+
"total": 0,
|
|
1626
|
+
"covered": 0,
|
|
1627
|
+
"missing": []
|
|
1628
|
+
},
|
|
1629
|
+
"slots": {
|
|
1630
|
+
"total": 2,
|
|
1631
|
+
"covered": 1,
|
|
1632
|
+
"missing": [
|
|
1633
|
+
"indicator"
|
|
1634
|
+
]
|
|
1635
|
+
},
|
|
1636
|
+
"methods": {
|
|
1637
|
+
"total": 0,
|
|
1638
|
+
"covered": 0,
|
|
1639
|
+
"missing": []
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1607
1642
|
{
|
|
1608
1643
|
"id": "MegaMenu",
|
|
1609
1644
|
"exportName": "MMegaMenu",
|
|
@@ -3194,8 +3229,8 @@
|
|
|
3194
3229
|
}
|
|
3195
3230
|
],
|
|
3196
3231
|
"summary": {
|
|
3197
|
-
"components":
|
|
3198
|
-
"componentsWithMissingCoverage":
|
|
3199
|
-
"totalExamples":
|
|
3232
|
+
"components": 93,
|
|
3233
|
+
"componentsWithMissingCoverage": 88,
|
|
3234
|
+
"totalExamples": 803
|
|
3200
3235
|
}
|
|
3201
3236
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/**
|
|
3
3
|
* 黄金样例:仪表盘页
|
|
4
|
-
* @see DESIGN.md §
|
|
4
|
+
* @see DESIGN.md · morya-ui-pages references/page-layouts.md · visual-craft § Ops polish
|
|
5
5
|
*/
|
|
6
6
|
import {
|
|
7
7
|
MBreadcrumb,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
MPageHeader,
|
|
17
17
|
MPagePlaceholder,
|
|
18
18
|
MPageStat,
|
|
19
|
+
MStatus,
|
|
19
20
|
MTable,
|
|
20
21
|
MTag,
|
|
21
22
|
zhCN,
|
|
@@ -32,7 +33,7 @@ const recentColumns = [
|
|
|
32
33
|
{ key: 'id', label: '工单号', width: 96 },
|
|
33
34
|
{ key: 'title', label: '标题' },
|
|
34
35
|
{ key: 'priority', label: '优先级', width: 96 },
|
|
35
|
-
{ key: 'status', label: '状态', width:
|
|
36
|
+
{ key: 'status', label: '状态', width: 110 },
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
const recentRows = [
|
|
@@ -47,11 +48,23 @@ function prioritySeverity(p: string) {
|
|
|
47
48
|
return 'secondary'
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
function priorityLabel(p: string) {
|
|
52
|
+
if (p === 'high') return '高'
|
|
53
|
+
if (p === 'medium') return '中'
|
|
54
|
+
return '低'
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
function statusLabel(s: string) {
|
|
51
58
|
if (s === 'open') return '待处理'
|
|
52
59
|
if (s === 'progress') return '进行中'
|
|
53
60
|
return '已完成'
|
|
54
61
|
}
|
|
62
|
+
|
|
63
|
+
function statusSeverity(s: string) {
|
|
64
|
+
if (s === 'open') return 'warn'
|
|
65
|
+
if (s === 'progress') return 'info'
|
|
66
|
+
return 'success'
|
|
67
|
+
}
|
|
55
68
|
</script>
|
|
56
69
|
|
|
57
70
|
<template>
|
|
@@ -63,7 +76,10 @@ function statusLabel(s: string) {
|
|
|
63
76
|
|
|
64
77
|
<MLayoutContent>
|
|
65
78
|
<MPageContent density="spacious">
|
|
66
|
-
<MPageHeader
|
|
79
|
+
<MPageHeader
|
|
80
|
+
title="运营概览"
|
|
81
|
+
description="关注今日活跃与待处理工单,异常优先下钻。"
|
|
82
|
+
/>
|
|
67
83
|
|
|
68
84
|
<MGrid :cols="4" :x-gap="16" :y-gap="16" responsive="screen">
|
|
69
85
|
<MGridItem v-for="item in stats" :key="item.label" :span="1">
|
|
@@ -77,20 +93,37 @@ function statusLabel(s: string) {
|
|
|
77
93
|
</MGridItem>
|
|
78
94
|
</MGrid>
|
|
79
95
|
|
|
80
|
-
<MGrid :cols="2" :x-gap="16" :y-gap="16">
|
|
96
|
+
<MGrid :cols="2" :x-gap="16" :y-gap="16" responsive="screen">
|
|
81
97
|
<MGridItem :span="1">
|
|
82
98
|
<MCard title="趋势概览">
|
|
83
|
-
<MPagePlaceholder
|
|
99
|
+
<MPagePlaceholder
|
|
100
|
+
aria-label="图表占位"
|
|
101
|
+
description="接入图表组件后展示近 7 日活跃与转化。"
|
|
102
|
+
/>
|
|
84
103
|
</MCard>
|
|
85
104
|
</MGridItem>
|
|
86
105
|
<MGridItem :span="1">
|
|
87
106
|
<MCard title="最近工单">
|
|
88
|
-
<MTable
|
|
107
|
+
<MTable
|
|
108
|
+
:columns="recentColumns"
|
|
109
|
+
:rows="recentRows"
|
|
110
|
+
size="small"
|
|
111
|
+
:paginator="false"
|
|
112
|
+
bordered
|
|
113
|
+
row-key="id"
|
|
114
|
+
aria-label="最近工单"
|
|
115
|
+
>
|
|
89
116
|
<template #cell-priority="{ value }">
|
|
90
|
-
<MTag
|
|
117
|
+
<MTag
|
|
118
|
+
:value="priorityLabel(String(value))"
|
|
119
|
+
:severity="prioritySeverity(String(value))"
|
|
120
|
+
/>
|
|
91
121
|
</template>
|
|
92
122
|
<template #cell-status="{ value }">
|
|
93
|
-
<
|
|
123
|
+
<MStatus
|
|
124
|
+
:label="statusLabel(String(value))"
|
|
125
|
+
:severity="statusSeverity(String(value))"
|
|
126
|
+
/>
|
|
94
127
|
</template>
|
|
95
128
|
</MTable>
|
|
96
129
|
</MCard>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/**
|
|
3
3
|
* 黄金样例:列表空状态(Flow)
|
|
4
|
-
* @see DESIGN.md
|
|
4
|
+
* @see DESIGN.md · page-layouts.md · surfaces § Flow
|
|
5
5
|
* 可嵌在列表页 MPageContent / MTable #empty 中;此处给出完整可运行骨架。
|
|
6
6
|
*/
|
|
7
7
|
import {
|
|
@@ -53,6 +53,10 @@ import {
|
|
|
53
53
|
|
|
54
54
|
<style scoped>
|
|
55
55
|
.empty-state-shell {
|
|
56
|
+
display: grid;
|
|
57
|
+
place-items: center;
|
|
58
|
+
min-height: 18rem;
|
|
59
|
+
padding: var(--m-space-8) var(--m-space-6);
|
|
56
60
|
border: 1px dashed color-mix(in srgb, var(--m-color-border) 80%, var(--m-color-primary));
|
|
57
61
|
border-radius: var(--m-radius-md);
|
|
58
62
|
background:
|
|
@@ -63,4 +67,21 @@ import {
|
|
|
63
67
|
),
|
|
64
68
|
var(--m-color-surface);
|
|
65
69
|
}
|
|
70
|
+
|
|
71
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
72
|
+
.empty-state-shell {
|
|
73
|
+
animation: empty-in 400ms ease both;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@keyframes empty-in {
|
|
78
|
+
from {
|
|
79
|
+
opacity: 0;
|
|
80
|
+
transform: translateY(0.35rem);
|
|
81
|
+
}
|
|
82
|
+
to {
|
|
83
|
+
opacity: 1;
|
|
84
|
+
transform: translateY(0);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
66
87
|
</style>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/**
|
|
3
3
|
* 黄金样例:营销落地页(Express)
|
|
4
|
-
* @see DESIGN.md
|
|
4
|
+
* @see DESIGN.md · page-layouts.md · surfaces § Express
|
|
5
5
|
* 首屏单一任务;控件用 M*;色彩只走 --m-*;避开 AI 默认脸。
|
|
6
6
|
*/
|
|
7
7
|
import { MAccordion, MButton, MConfigProvider, MTag, zhCN } from 'morya-ui'
|
|
@@ -219,6 +219,36 @@ const faqTabs = [
|
|
|
219
219
|
font-weight: 600;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
223
|
+
.landing-hero__track span {
|
|
224
|
+
animation: landing-fade-up 480ms ease both;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.landing-hero__track span:nth-child(2) {
|
|
228
|
+
animation-delay: 60ms;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.landing-hero__track span:nth-child(3) {
|
|
232
|
+
animation-delay: 120ms;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.landing-hero__track span:nth-child(4) {
|
|
236
|
+
animation-delay: 180ms;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@keyframes landing-fade-up {
|
|
241
|
+
from {
|
|
242
|
+
opacity: 0;
|
|
243
|
+
transform: translateY(0.4rem);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
to {
|
|
247
|
+
opacity: 1;
|
|
248
|
+
transform: translateY(0);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
222
252
|
.landing-section {
|
|
223
253
|
padding: clamp(2.5rem, 6vw, 4rem) clamp(1.25rem, 4vw, 3rem);
|
|
224
254
|
max-width: 72rem;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/**
|
|
3
3
|
* 黄金样例:列表页
|
|
4
|
-
* @see DESIGN.md §
|
|
4
|
+
* @see DESIGN.md · morya-ui-pages references/page-layouts.md · visual-craft § Ops polish
|
|
5
5
|
*/
|
|
6
6
|
import {
|
|
7
7
|
MBreadcrumb,
|
|
8
8
|
MButton,
|
|
9
9
|
MConfigProvider,
|
|
10
|
+
MEmpty,
|
|
10
11
|
MInput,
|
|
11
12
|
MLayout,
|
|
12
13
|
MLayoutContent,
|
|
@@ -18,8 +19,8 @@ import {
|
|
|
18
19
|
MPageToolbar,
|
|
19
20
|
MSelect,
|
|
20
21
|
MSpace,
|
|
22
|
+
MStatus,
|
|
21
23
|
MTable,
|
|
22
|
-
MTag,
|
|
23
24
|
zhCN,
|
|
24
25
|
} from 'morya-ui'
|
|
25
26
|
import { ref } from 'vue'
|
|
@@ -31,6 +32,7 @@ const siderCollapsed = ref(false)
|
|
|
31
32
|
const menuModel = [
|
|
32
33
|
{ key: 'users', label: '用户管理', icon: 'user', to: '/users' },
|
|
33
34
|
{ key: 'roles', label: '角色管理', icon: 'shield', to: '/roles' },
|
|
35
|
+
{ key: 'settings', label: '系统设置', icon: 'settings', to: '/settings' },
|
|
34
36
|
]
|
|
35
37
|
|
|
36
38
|
const statusOptions = [
|
|
@@ -41,9 +43,9 @@ const statusOptions = [
|
|
|
41
43
|
|
|
42
44
|
const columns = [
|
|
43
45
|
{ key: 'name', label: '名称' },
|
|
44
|
-
{ key: 'status', label: '状态' },
|
|
45
|
-
{ key: 'updatedAt', label: '更新时间' },
|
|
46
|
-
{ key: 'actions', label: '操作', width:
|
|
46
|
+
{ key: 'status', label: '状态', width: 120 },
|
|
47
|
+
{ key: 'updatedAt', label: '更新时间', width: 140 },
|
|
48
|
+
{ key: 'actions', label: '操作', width: 148 },
|
|
47
49
|
]
|
|
48
50
|
|
|
49
51
|
const rows = [
|
|
@@ -104,7 +106,7 @@ const rows = [
|
|
|
104
106
|
<MTable
|
|
105
107
|
:columns="columns"
|
|
106
108
|
:rows="rows"
|
|
107
|
-
:rows-per-page="
|
|
109
|
+
:rows-per-page="5"
|
|
108
110
|
paginator
|
|
109
111
|
striped
|
|
110
112
|
bordered
|
|
@@ -112,22 +114,33 @@ const rows = [
|
|
|
112
114
|
aria-label="用户列表"
|
|
113
115
|
>
|
|
114
116
|
<template #cell-status="{ value }">
|
|
115
|
-
<
|
|
117
|
+
<MStatus
|
|
118
|
+
:label="value === 'active' ? '启用' : '停用'"
|
|
119
|
+
:severity="value === 'active' ? 'success' : 'secondary'"
|
|
120
|
+
/>
|
|
116
121
|
</template>
|
|
117
122
|
<template #cell-actions>
|
|
118
123
|
<MSpace>
|
|
119
|
-
<MButton severity="secondary" size="small">
|
|
124
|
+
<MButton severity="secondary" size="small" text>
|
|
120
125
|
编辑
|
|
121
126
|
</MButton>
|
|
122
|
-
<MButton severity="danger" size="small">
|
|
127
|
+
<MButton severity="danger" size="small" text>
|
|
123
128
|
删除
|
|
124
129
|
</MButton>
|
|
125
130
|
</MSpace>
|
|
126
131
|
</template>
|
|
127
132
|
<template #empty>
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
<MEmpty
|
|
134
|
+
title="还没有用户"
|
|
135
|
+
description="创建第一个用户后,即可分配角色与权限。"
|
|
136
|
+
icon="user"
|
|
137
|
+
>
|
|
138
|
+
<template #extra>
|
|
139
|
+
<MButton severity="primary">
|
|
140
|
+
新建用户
|
|
141
|
+
</MButton>
|
|
142
|
+
</template>
|
|
143
|
+
</MEmpty>
|
|
131
144
|
</template>
|
|
132
145
|
</MTable>
|
|
133
146
|
</MPageContent>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/**
|
|
3
3
|
* 黄金样例:登录页(Account + 轻量品牌)
|
|
4
|
-
* @see DESIGN.md §
|
|
4
|
+
* @see DESIGN.md · surfaces § Account · visual-craft § Atmosphere
|
|
5
5
|
*/
|
|
6
6
|
import {
|
|
7
7
|
MButton,
|
|
@@ -56,7 +56,6 @@ async function onSubmit() {
|
|
|
56
56
|
<p>使用工作邮箱进入后台。</p>
|
|
57
57
|
</header>
|
|
58
58
|
|
|
59
|
-
<!-- 表单级常驻错误:token 样式告警条(字段错误优先用 errorMessage) -->
|
|
60
59
|
<p v-if="formError" class="login-alert" role="alert">
|
|
61
60
|
{{ formError }}
|
|
62
61
|
</p>
|
|
@@ -82,7 +81,7 @@ async function onSubmit() {
|
|
|
82
81
|
</MFormItem>
|
|
83
82
|
|
|
84
83
|
<MSpace style="margin-top: var(--m-space-2)" alignment="center">
|
|
85
|
-
<MButton type="submit" label="登录" :loading="submitting" />
|
|
84
|
+
<MButton type="submit" label="登录" severity="primary" :loading="submitting" />
|
|
86
85
|
<MButton type="button" label="忘记密码" severity="secondary" text />
|
|
87
86
|
</MSpace>
|
|
88
87
|
</MForm>
|
|
@@ -102,21 +101,45 @@ async function onSubmit() {
|
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
.login-brand {
|
|
104
|
+
position: relative;
|
|
105
105
|
display: flex;
|
|
106
106
|
flex-direction: column;
|
|
107
107
|
justify-content: flex-end;
|
|
108
108
|
gap: var(--m-space-4);
|
|
109
109
|
padding: clamp(2rem, 6vw, 4.5rem);
|
|
110
|
+
overflow: hidden;
|
|
110
111
|
background:
|
|
112
|
+
radial-gradient(
|
|
113
|
+
80% 60% at 10% 20%,
|
|
114
|
+
color-mix(in srgb, var(--m-color-primary) 22%, transparent),
|
|
115
|
+
transparent 55%
|
|
116
|
+
),
|
|
111
117
|
linear-gradient(
|
|
112
118
|
165deg,
|
|
113
|
-
color-mix(in srgb, var(--m-color-primary)
|
|
119
|
+
color-mix(in srgb, var(--m-color-primary) 16%, var(--m-color-surface)) 0%,
|
|
114
120
|
var(--m-color-surface) 55%,
|
|
115
121
|
color-mix(in srgb, var(--m-color-border) 35%, var(--m-color-surface)) 100%
|
|
116
122
|
);
|
|
117
123
|
border-right: 1px solid var(--m-color-border);
|
|
118
124
|
}
|
|
119
125
|
|
|
126
|
+
.login-brand::after {
|
|
127
|
+
content: '';
|
|
128
|
+
position: absolute;
|
|
129
|
+
inset: auto -10% -20% 40%;
|
|
130
|
+
height: 55%;
|
|
131
|
+
border-radius: 50%;
|
|
132
|
+
background: color-mix(in srgb, var(--m-color-primary) 12%, transparent);
|
|
133
|
+
pointer-events: none;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.login-brand__mark,
|
|
137
|
+
.login-brand__title,
|
|
138
|
+
.login-brand__lead {
|
|
139
|
+
position: relative;
|
|
140
|
+
z-index: 1;
|
|
141
|
+
}
|
|
142
|
+
|
|
120
143
|
.login-brand__mark {
|
|
121
144
|
margin: 0;
|
|
122
145
|
font-size: 0.8125rem;
|
|
@@ -177,6 +200,23 @@ async function onSubmit() {
|
|
|
177
200
|
line-height: 1.45;
|
|
178
201
|
}
|
|
179
202
|
|
|
203
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
204
|
+
.login-panel {
|
|
205
|
+
animation: login-panel-in 420ms ease both;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@keyframes login-panel-in {
|
|
210
|
+
from {
|
|
211
|
+
opacity: 0;
|
|
212
|
+
transform: translateY(0.5rem);
|
|
213
|
+
}
|
|
214
|
+
to {
|
|
215
|
+
opacity: 1;
|
|
216
|
+
transform: translateY(0);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
180
220
|
@media (max-width: 768px) {
|
|
181
221
|
.login-shell {
|
|
182
222
|
grid-template-columns: 1fr;
|
|
@@ -199,6 +199,16 @@ describe('@morya-ui/mcp handlers', () => {
|
|
|
199
199
|
expect(result.id).toBe('overlay-choice');
|
|
200
200
|
expect(result.options.some((option) => option.component === 'Drawer')).toBe(true);
|
|
201
201
|
});
|
|
202
|
+
it('covers current selection, status, empty, and menu guides', () => {
|
|
203
|
+
const selection = read(handlers.recommendComponent({ decision: 'selection-choice' }));
|
|
204
|
+
expect(selection.options.map((option) => option.component)).toEqual(expect.arrayContaining(['Select', 'CascadeSelect', 'Listbox', 'SelectButton', 'Radio']));
|
|
205
|
+
const status = read(handlers.recommendComponent({ decision: 'status-label-choice' }));
|
|
206
|
+
expect(status.id).toBe('status-label-choice');
|
|
207
|
+
const empty = read(handlers.recommendComponent({ decision: 'empty-result-choice' }));
|
|
208
|
+
expect(empty.options.map((option) => option.component)).toEqual(['Empty', 'Result']);
|
|
209
|
+
const menu = read(handlers.recommendComponent({ decision: 'action-menu-choice' }));
|
|
210
|
+
expect(menu.options.some((option) => option.component === 'ContextMenu')).toBe(true);
|
|
211
|
+
});
|
|
202
212
|
it('exposes catalog health in version metadata', () => {
|
|
203
213
|
const result = read(handlers.version());
|
|
204
214
|
expect(result.health.ok).toBe(true);
|