@morya-ui/setup 0.2.6 → 0.2.8
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 +23 -10
- package/package.json +1 -1
- package/src/cli.mjs +90 -32
- package/src/copy-template.mjs +18 -2
- package/src/fs-utils.mjs +2 -1
- package/src/styles.mjs +2 -87
- package/template/.agents/skills/morya-ui-pages/SKILL.md +1 -3
- package/template/.agents/skills/morya-ui-pages/references/component-index.md +7 -1
- package/template/.agents/skills/morya-ui-pages/references/design-system.md +1 -1
- package/template/.agents/skills/morya-ui-pages/references/feedback.md +1 -1
- package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +10 -10
- package/template/.agents/skills/morya-ui-pages/references/surfaces.md +3 -3
- package/template/.cursor/rules/component-usage.mdc +2 -2
- package/template/.cursor/rules/design-system.mdc +5 -5
- package/template/.cursor/rules/page-layout.mdc +7 -9
- package/template/DESIGN.md +15 -15
- package/template/design-tokens/tokens.css +0 -55
- package/template/design-tokens/tokens.json +0 -77
- package/template/docs/components.md +0 -145
- package/template/docs/feedback-message-vs-toast.md +0 -103
- package/template/docs/golden-pages/dashboard-page.vue +0 -103
- package/template/docs/golden-pages/empty-state.vue +0 -66
- package/template/docs/golden-pages/form-page.vue +0 -107
- package/template/docs/golden-pages/landing-page.vue +0 -328
- package/template/docs/golden-pages/list-page.vue +0 -138
- package/template/docs/golden-pages/login-page.vue +0 -191
- package/template/src/examples/DashboardPageExample.vue +0 -103
- package/template/src/examples/EmptyStateExample.vue +0 -66
- package/template/src/examples/FormPageExample.vue +0 -107
- package/template/src/examples/LandingPageExample.vue +0 -328
- package/template/src/examples/ListPageExample.vue +0 -138
- package/template/src/examples/LoginPageExample.vue +0 -191
- package/template/src/styles/morya-app-shell.css +0 -6
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* 黄金样例:表单页
|
|
4
|
-
* @see DESIGN.md §3
|
|
5
|
-
*/
|
|
6
|
-
import {
|
|
7
|
-
MBreadcrumb,
|
|
8
|
-
MButton,
|
|
9
|
-
MConfigProvider,
|
|
10
|
-
MDatePicker,
|
|
11
|
-
MForm,
|
|
12
|
-
MFormItem,
|
|
13
|
-
MInput,
|
|
14
|
-
MLayout,
|
|
15
|
-
MLayoutContent,
|
|
16
|
-
MLayoutHeader,
|
|
17
|
-
MPageContent,
|
|
18
|
-
MPageHeader,
|
|
19
|
-
MPageSection,
|
|
20
|
-
MSelect,
|
|
21
|
-
MSpace,
|
|
22
|
-
MSwitch,
|
|
23
|
-
MTextarea,
|
|
24
|
-
zhCN,
|
|
25
|
-
} from 'morya-ui'
|
|
26
|
-
import { reactive, ref } from 'vue'
|
|
27
|
-
|
|
28
|
-
const submitting = ref(false)
|
|
29
|
-
|
|
30
|
-
const model = reactive({
|
|
31
|
-
name: '',
|
|
32
|
-
email: '',
|
|
33
|
-
role: undefined as string | undefined,
|
|
34
|
-
active: true,
|
|
35
|
-
joinedAt: null as string | null,
|
|
36
|
-
bio: '',
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
const roleOptions = [
|
|
40
|
-
{ label: '管理员', value: 'admin' },
|
|
41
|
-
{ label: '成员', value: 'member' },
|
|
42
|
-
]
|
|
43
|
-
|
|
44
|
-
async function onSubmit() {
|
|
45
|
-
submitting.value = true
|
|
46
|
-
try {
|
|
47
|
-
// await api.save(model)
|
|
48
|
-
} finally {
|
|
49
|
-
submitting.value = false
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
</script>
|
|
53
|
-
|
|
54
|
-
<template>
|
|
55
|
-
<MConfigProvider :locale="zhCN">
|
|
56
|
-
<MLayout fill-viewport>
|
|
57
|
-
<MLayoutHeader padding="var(--m-space-4) var(--m-space-6)">
|
|
58
|
-
<MBreadcrumb :model="[{ label: '首页', to: '/' }, { label: '用户管理', to: '/users' }, { label: '新建用户' }]" />
|
|
59
|
-
</MLayoutHeader>
|
|
60
|
-
|
|
61
|
-
<MLayoutContent>
|
|
62
|
-
<MPageContent width="narrow">
|
|
63
|
-
<MPageHeader title="新建用户" description="填写基本信息并分配角色。" />
|
|
64
|
-
|
|
65
|
-
<MPageSection variant="form">
|
|
66
|
-
<MForm @submit="onSubmit">
|
|
67
|
-
<MFormItem label="姓名" name="name" required>
|
|
68
|
-
<MInput v-model="model.name" placeholder="请输入姓名" fluid />
|
|
69
|
-
</MFormItem>
|
|
70
|
-
|
|
71
|
-
<MFormItem label="邮箱" name="email" required>
|
|
72
|
-
<MInput v-model="model.email" type="email" placeholder="name@example.com" fluid />
|
|
73
|
-
</MFormItem>
|
|
74
|
-
|
|
75
|
-
<MFormItem label="角色" name="role" required>
|
|
76
|
-
<MSelect v-model="model.role" :options="roleOptions" placeholder="请选择角色" fluid />
|
|
77
|
-
</MFormItem>
|
|
78
|
-
|
|
79
|
-
<MFormItem label="入职日期" name="joinedAt">
|
|
80
|
-
<MDatePicker v-model="model.joinedAt" placeholder="选择日期" fluid />
|
|
81
|
-
</MFormItem>
|
|
82
|
-
|
|
83
|
-
<MFormItem label="启用账号" name="active">
|
|
84
|
-
<MSwitch v-model="model.active" />
|
|
85
|
-
</MFormItem>
|
|
86
|
-
|
|
87
|
-
<MFormItem label="简介" name="bio">
|
|
88
|
-
<MTextarea v-model="model.bio" :rows="4" placeholder="可选" fluid />
|
|
89
|
-
</MFormItem>
|
|
90
|
-
|
|
91
|
-
<MPageSection variant="actions">
|
|
92
|
-
<MSpace>
|
|
93
|
-
<MButton native-type="submit" severity="primary" :loading="submitting">
|
|
94
|
-
保存
|
|
95
|
-
</MButton>
|
|
96
|
-
<MButton severity="secondary">
|
|
97
|
-
取消
|
|
98
|
-
</MButton>
|
|
99
|
-
</MSpace>
|
|
100
|
-
</MPageSection>
|
|
101
|
-
</MForm>
|
|
102
|
-
</MPageSection>
|
|
103
|
-
</MPageContent>
|
|
104
|
-
</MLayoutContent>
|
|
105
|
-
</MLayout>
|
|
106
|
-
</MConfigProvider>
|
|
107
|
-
</template>
|
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* 黄金样例:营销落地页(Express)
|
|
4
|
-
* @see DESIGN.md §3 · morya-ui-pages surfaces § Express
|
|
5
|
-
* 首屏单一任务;控件用 M*;色彩只走 --m-*;避开 AI 默认脸。
|
|
6
|
-
*/
|
|
7
|
-
import { MAccordion, MButton, MConfigProvider, MTag, zhCN } from 'morya-ui'
|
|
8
|
-
|
|
9
|
-
const faqTabs = [
|
|
10
|
-
{ value: 'stack', header: '必须用特定框架吗?' },
|
|
11
|
-
{ value: 'hosting', header: '流水线跑在哪里?' },
|
|
12
|
-
{ value: 'migrate', header: '如何从现有 CI 迁过来?' },
|
|
13
|
-
]
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<template>
|
|
17
|
-
<MConfigProvider :locale="zhCN">
|
|
18
|
-
<div class="landing">
|
|
19
|
-
<header class="landing-nav">
|
|
20
|
-
<span class="landing-nav__brand">流水线 CI</span>
|
|
21
|
-
<nav class="landing-nav__links" aria-label="页面导航">
|
|
22
|
-
<a href="#why">为何选择</a>
|
|
23
|
-
<a href="#capabilities">能力</a>
|
|
24
|
-
<a href="#faq">常见问题</a>
|
|
25
|
-
</nav>
|
|
26
|
-
<MButton label="免费试用" size="small" />
|
|
27
|
-
</header>
|
|
28
|
-
|
|
29
|
-
<section class="landing-hero" aria-labelledby="hero-title">
|
|
30
|
-
<p class="landing-hero__brand">流水线 CI</p>
|
|
31
|
-
<h1 id="hero-title">把每次提交变成可回放的交付</h1>
|
|
32
|
-
<p class="landing-hero__lead">
|
|
33
|
-
为工程团队准备的构建与发布编排。少点配置,多看结果。
|
|
34
|
-
</p>
|
|
35
|
-
<div class="landing-hero__cta">
|
|
36
|
-
<MButton label="开始使用" />
|
|
37
|
-
<MButton label="查看文档" severity="secondary" text />
|
|
38
|
-
</div>
|
|
39
|
-
<div class="landing-hero__visual" role="img" aria-label="构建时间线示意">
|
|
40
|
-
<div class="landing-hero__track">
|
|
41
|
-
<span>检出</span>
|
|
42
|
-
<span>测试</span>
|
|
43
|
-
<span>制品</span>
|
|
44
|
-
<span>发布</span>
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
</section>
|
|
48
|
-
|
|
49
|
-
<section id="why" class="landing-section">
|
|
50
|
-
<h2>为何选择</h2>
|
|
51
|
-
<p class="landing-section__lead">面向真实仓库节奏,而不是演示用的仪表盘皮肤。</p>
|
|
52
|
-
<ul class="landing-points">
|
|
53
|
-
<li>
|
|
54
|
-
<strong>可回放</strong>
|
|
55
|
-
<span>每次运行保留完整日志与产物索引,失败可复现。</span>
|
|
56
|
-
</li>
|
|
57
|
-
<li>
|
|
58
|
-
<strong>少样板</strong>
|
|
59
|
-
<span>默认流水线覆盖检出、缓存与并行矩阵,按需覆盖。</span>
|
|
60
|
-
</li>
|
|
61
|
-
<li>
|
|
62
|
-
<strong>权限清楚</strong>
|
|
63
|
-
<span>环境、密钥与审批流按仓库边界隔离。</span>
|
|
64
|
-
</li>
|
|
65
|
-
</ul>
|
|
66
|
-
</section>
|
|
67
|
-
|
|
68
|
-
<section id="capabilities" class="landing-section landing-section--alt">
|
|
69
|
-
<h2>能力</h2>
|
|
70
|
-
<p class="landing-section__lead">用组件库控件表达交互,不引入第二套 UI。</p>
|
|
71
|
-
<div class="landing-cards">
|
|
72
|
-
<article>
|
|
73
|
-
<MTag value="构建" severity="info" />
|
|
74
|
-
<h3>并行矩阵</h3>
|
|
75
|
-
<p>按系统与 Node 版本展开任务,失败任务可单独重跑。</p>
|
|
76
|
-
</article>
|
|
77
|
-
<article>
|
|
78
|
-
<MTag value="发布" severity="success" />
|
|
79
|
-
<h3>环境门禁</h3>
|
|
80
|
-
<p>生产发布需要审批与变更说明,记录谁在何时放行。</p>
|
|
81
|
-
</article>
|
|
82
|
-
<article>
|
|
83
|
-
<MTag value="观测" />
|
|
84
|
-
<h3>耗时对比</h3>
|
|
85
|
-
<p>同分支历史耗时并排,找出突然变慢的步骤。</p>
|
|
86
|
-
</article>
|
|
87
|
-
</div>
|
|
88
|
-
</section>
|
|
89
|
-
|
|
90
|
-
<section id="faq" class="landing-section">
|
|
91
|
-
<h2>常见问题</h2>
|
|
92
|
-
<MAccordion :tabs="faqTabs" default-value="stack">
|
|
93
|
-
<template #stack>
|
|
94
|
-
<p class="landing-faq">
|
|
95
|
-
任意可容器化的仓库即可。示例以 Vue / Node 为主,不绑定单一前端脚手架。
|
|
96
|
-
</p>
|
|
97
|
-
</template>
|
|
98
|
-
<template #hosting>
|
|
99
|
-
<p class="landing-faq">
|
|
100
|
-
可自托管 runner,也可使用托管队列。密钥不进入日志明文。
|
|
101
|
-
</p>
|
|
102
|
-
</template>
|
|
103
|
-
<template #migrate>
|
|
104
|
-
<p class="landing-faq">
|
|
105
|
-
从现有 YAML 映射阶段与缓存键;保留原有制品路径可降低切换成本。
|
|
106
|
-
</p>
|
|
107
|
-
</template>
|
|
108
|
-
</MAccordion>
|
|
109
|
-
</section>
|
|
110
|
-
|
|
111
|
-
<footer class="landing-footer">
|
|
112
|
-
<span>流水线 CI</span>
|
|
113
|
-
<MButton label="联系销售" severity="secondary" text />
|
|
114
|
-
</footer>
|
|
115
|
-
</div>
|
|
116
|
-
</MConfigProvider>
|
|
117
|
-
</template>
|
|
118
|
-
|
|
119
|
-
<style scoped>
|
|
120
|
-
.landing {
|
|
121
|
-
min-height: 100vh;
|
|
122
|
-
background: var(--m-color-surface);
|
|
123
|
-
color: var(--m-color-text);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.landing-nav {
|
|
127
|
-
display: flex;
|
|
128
|
-
align-items: center;
|
|
129
|
-
gap: var(--m-space-4);
|
|
130
|
-
padding: var(--m-space-4) clamp(1.25rem, 4vw, 3rem);
|
|
131
|
-
border-bottom: 1px solid var(--m-color-border);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.landing-nav__brand {
|
|
135
|
-
font-weight: 700;
|
|
136
|
-
letter-spacing: -0.02em;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
.landing-nav__links {
|
|
140
|
-
display: flex;
|
|
141
|
-
flex: 1;
|
|
142
|
-
gap: var(--m-space-4);
|
|
143
|
-
margin-left: var(--m-space-2);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.landing-nav__links a {
|
|
147
|
-
color: var(--m-color-text-muted);
|
|
148
|
-
text-decoration: none;
|
|
149
|
-
font-size: 0.9375rem;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
.landing-nav__links a:hover {
|
|
153
|
-
color: var(--m-color-primary);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
.landing-hero {
|
|
157
|
-
display: grid;
|
|
158
|
-
gap: var(--m-space-4);
|
|
159
|
-
padding: clamp(2.5rem, 8vw, 5.5rem) clamp(1.25rem, 4vw, 3rem) clamp(3rem, 8vw, 5rem);
|
|
160
|
-
max-width: 72rem;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.landing-hero__brand {
|
|
164
|
-
margin: 0;
|
|
165
|
-
font-size: 0.8125rem;
|
|
166
|
-
letter-spacing: 0.12em;
|
|
167
|
-
text-transform: uppercase;
|
|
168
|
-
color: var(--m-color-text-muted);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.landing-hero h1 {
|
|
172
|
-
margin: 0;
|
|
173
|
-
max-width: 14em;
|
|
174
|
-
font-size: clamp(2.25rem, 5vw, 3.5rem);
|
|
175
|
-
font-weight: 700;
|
|
176
|
-
line-height: 1.12;
|
|
177
|
-
letter-spacing: -0.035em;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.landing-hero__lead {
|
|
181
|
-
margin: 0;
|
|
182
|
-
max-width: 36rem;
|
|
183
|
-
font-size: 1.125rem;
|
|
184
|
-
line-height: 1.55;
|
|
185
|
-
color: var(--m-color-text-muted);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.landing-hero__cta {
|
|
189
|
-
display: flex;
|
|
190
|
-
flex-wrap: wrap;
|
|
191
|
-
gap: var(--m-space-3);
|
|
192
|
-
margin-top: var(--m-space-2);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.landing-hero__visual {
|
|
196
|
-
margin-top: var(--m-space-5);
|
|
197
|
-
padding: var(--m-space-5);
|
|
198
|
-
border: 1px solid var(--m-color-border);
|
|
199
|
-
border-radius: var(--m-radius-md);
|
|
200
|
-
background:
|
|
201
|
-
linear-gradient(
|
|
202
|
-
135deg,
|
|
203
|
-
color-mix(in srgb, var(--m-color-primary) 12%, var(--m-color-surface)),
|
|
204
|
-
var(--m-color-surface) 60%
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.landing-hero__track {
|
|
209
|
-
display: grid;
|
|
210
|
-
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
211
|
-
gap: var(--m-space-3);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.landing-hero__track span {
|
|
215
|
-
padding: var(--m-space-3) var(--m-space-4);
|
|
216
|
-
border-left: 3px solid var(--m-color-primary);
|
|
217
|
-
background: color-mix(in srgb, var(--m-color-surface) 80%, transparent);
|
|
218
|
-
font-size: 0.875rem;
|
|
219
|
-
font-weight: 600;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.landing-section {
|
|
223
|
-
padding: clamp(2.5rem, 6vw, 4rem) clamp(1.25rem, 4vw, 3rem);
|
|
224
|
-
max-width: 72rem;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
.landing-section--alt {
|
|
228
|
-
border-block: 1px solid var(--m-color-border);
|
|
229
|
-
background: color-mix(in srgb, var(--m-color-border) 18%, var(--m-color-surface));
|
|
230
|
-
max-width: none;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
.landing-section h2 {
|
|
234
|
-
margin: 0 0 var(--m-space-3);
|
|
235
|
-
font-size: 1.75rem;
|
|
236
|
-
letter-spacing: -0.02em;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.landing-section__lead {
|
|
240
|
-
margin: 0 0 var(--m-space-5);
|
|
241
|
-
max-width: 36rem;
|
|
242
|
-
color: var(--m-color-text-muted);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
.landing-points {
|
|
246
|
-
list-style: none;
|
|
247
|
-
margin: 0;
|
|
248
|
-
padding: 0;
|
|
249
|
-
display: grid;
|
|
250
|
-
gap: var(--m-space-4);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
.landing-points li {
|
|
254
|
-
display: grid;
|
|
255
|
-
gap: var(--m-space-2);
|
|
256
|
-
max-width: 40rem;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.landing-points strong {
|
|
260
|
-
font-size: 1.0625rem;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
.landing-points span {
|
|
264
|
-
color: var(--m-color-text-muted);
|
|
265
|
-
line-height: 1.55;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
.landing-cards {
|
|
269
|
-
display: grid;
|
|
270
|
-
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
271
|
-
gap: var(--m-space-4);
|
|
272
|
-
max-width: 72rem;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
.landing-cards article {
|
|
276
|
-
display: grid;
|
|
277
|
-
gap: var(--m-space-3);
|
|
278
|
-
padding: var(--m-space-5);
|
|
279
|
-
border: 1px solid var(--m-color-border);
|
|
280
|
-
border-radius: var(--m-radius-md);
|
|
281
|
-
background: var(--m-color-surface);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
.landing-cards h3 {
|
|
285
|
-
margin: 0;
|
|
286
|
-
font-size: 1.125rem;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
.landing-cards p {
|
|
290
|
-
margin: 0;
|
|
291
|
-
color: var(--m-color-text-muted);
|
|
292
|
-
line-height: 1.55;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
.landing-faq {
|
|
296
|
-
margin: 0;
|
|
297
|
-
color: var(--m-color-text-muted);
|
|
298
|
-
line-height: 1.55;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
.landing-footer {
|
|
302
|
-
display: flex;
|
|
303
|
-
align-items: center;
|
|
304
|
-
justify-content: space-between;
|
|
305
|
-
gap: var(--m-space-4);
|
|
306
|
-
padding: var(--m-space-5) clamp(1.25rem, 4vw, 3rem);
|
|
307
|
-
border-top: 1px solid var(--m-color-border);
|
|
308
|
-
color: var(--m-color-text-muted);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
@media (max-width: 900px) {
|
|
312
|
-
.landing-nav__links {
|
|
313
|
-
display: none;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
.landing-hero__track,
|
|
317
|
-
.landing-cards {
|
|
318
|
-
grid-template-columns: 1fr 1fr;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
@media (max-width: 560px) {
|
|
323
|
-
.landing-hero__track,
|
|
324
|
-
.landing-cards {
|
|
325
|
-
grid-template-columns: 1fr;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
</style>
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* 黄金样例:列表页
|
|
4
|
-
* @see DESIGN.md §3
|
|
5
|
-
*/
|
|
6
|
-
import {
|
|
7
|
-
MBreadcrumb,
|
|
8
|
-
MButton,
|
|
9
|
-
MConfigProvider,
|
|
10
|
-
MInput,
|
|
11
|
-
MLayout,
|
|
12
|
-
MLayoutContent,
|
|
13
|
-
MLayoutHeader,
|
|
14
|
-
MLayoutSider,
|
|
15
|
-
MMenu,
|
|
16
|
-
MPageContent,
|
|
17
|
-
MPageFilters,
|
|
18
|
-
MPageToolbar,
|
|
19
|
-
MSelect,
|
|
20
|
-
MSpace,
|
|
21
|
-
MTable,
|
|
22
|
-
MTag,
|
|
23
|
-
zhCN,
|
|
24
|
-
} from 'morya-ui'
|
|
25
|
-
import { ref } from 'vue'
|
|
26
|
-
|
|
27
|
-
const keyword = ref('')
|
|
28
|
-
const status = ref<string | undefined>()
|
|
29
|
-
const siderCollapsed = ref(false)
|
|
30
|
-
|
|
31
|
-
const menuModel = [
|
|
32
|
-
{ key: 'users', label: '用户管理', icon: 'user', to: '/users' },
|
|
33
|
-
{ key: 'roles', label: '角色管理', icon: 'shield', to: '/roles' },
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
const statusOptions = [
|
|
37
|
-
{ label: '全部', value: '' },
|
|
38
|
-
{ label: '启用', value: 'active' },
|
|
39
|
-
{ label: '停用', value: 'inactive' },
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
const columns = [
|
|
43
|
-
{ key: 'name', label: '名称' },
|
|
44
|
-
{ key: 'status', label: '状态' },
|
|
45
|
-
{ key: 'updatedAt', label: '更新时间' },
|
|
46
|
-
{ key: 'actions', label: '操作', width: 128 },
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
const rows = [
|
|
50
|
-
{ id: '1', name: '示例项目 A', status: 'active', updatedAt: '2026-09-01' },
|
|
51
|
-
{ id: '2', name: '示例项目 B', status: 'inactive', updatedAt: '2026-08-28' },
|
|
52
|
-
{ id: '3', name: '示例项目 C', status: 'active', updatedAt: '2026-08-25' },
|
|
53
|
-
{ id: '4', name: '示例项目 D', status: 'active', updatedAt: '2026-08-20' },
|
|
54
|
-
{ id: '5', name: '示例项目 E', status: 'inactive', updatedAt: '2026-08-15' },
|
|
55
|
-
]
|
|
56
|
-
</script>
|
|
57
|
-
|
|
58
|
-
<template>
|
|
59
|
-
<MConfigProvider :locale="zhCN">
|
|
60
|
-
<MLayout has-sider fill-viewport>
|
|
61
|
-
<MLayoutSider v-model:collapsed="siderCollapsed" bordered :collapsed-width="72">
|
|
62
|
-
<MMenu
|
|
63
|
-
:model="menuModel"
|
|
64
|
-
:collapsed="siderCollapsed"
|
|
65
|
-
:collapsed-width="72"
|
|
66
|
-
selected-key="users"
|
|
67
|
-
/>
|
|
68
|
-
</MLayoutSider>
|
|
69
|
-
|
|
70
|
-
<MLayout>
|
|
71
|
-
<MLayoutHeader padding="var(--m-space-4) var(--m-space-6)">
|
|
72
|
-
<MBreadcrumb :model="[{ label: '首页', to: '/' }, { label: '用户管理' }]" />
|
|
73
|
-
</MLayoutHeader>
|
|
74
|
-
|
|
75
|
-
<MLayoutContent>
|
|
76
|
-
<MPageContent>
|
|
77
|
-
<MPageFilters aria-label="筛选">
|
|
78
|
-
<MSpace wrap>
|
|
79
|
-
<MInput v-model="keyword" placeholder="搜索名称" clearable style="width: 14rem" />
|
|
80
|
-
<MSelect
|
|
81
|
-
v-model="status"
|
|
82
|
-
:options="statusOptions"
|
|
83
|
-
placeholder="状态"
|
|
84
|
-
clearable
|
|
85
|
-
style="width: 10rem"
|
|
86
|
-
/>
|
|
87
|
-
<MButton severity="primary">
|
|
88
|
-
查询
|
|
89
|
-
</MButton>
|
|
90
|
-
<MButton severity="secondary">
|
|
91
|
-
重置
|
|
92
|
-
</MButton>
|
|
93
|
-
</MSpace>
|
|
94
|
-
</MPageFilters>
|
|
95
|
-
|
|
96
|
-
<MPageToolbar title="用户管理">
|
|
97
|
-
<template #actions>
|
|
98
|
-
<MButton severity="primary">
|
|
99
|
-
新建用户
|
|
100
|
-
</MButton>
|
|
101
|
-
</template>
|
|
102
|
-
</MPageToolbar>
|
|
103
|
-
|
|
104
|
-
<MTable
|
|
105
|
-
:columns="columns"
|
|
106
|
-
:rows="rows"
|
|
107
|
-
:rows-per-page="3"
|
|
108
|
-
paginator
|
|
109
|
-
striped
|
|
110
|
-
bordered
|
|
111
|
-
row-key="id"
|
|
112
|
-
aria-label="用户列表"
|
|
113
|
-
>
|
|
114
|
-
<template #cell-status="{ value }">
|
|
115
|
-
<MTag :value="value === 'active' ? '启用' : '停用'" :severity="value === 'active' ? 'success' : 'secondary'" />
|
|
116
|
-
</template>
|
|
117
|
-
<template #cell-actions>
|
|
118
|
-
<MSpace>
|
|
119
|
-
<MButton severity="secondary" size="small">
|
|
120
|
-
编辑
|
|
121
|
-
</MButton>
|
|
122
|
-
<MButton severity="danger" size="small">
|
|
123
|
-
删除
|
|
124
|
-
</MButton>
|
|
125
|
-
</MSpace>
|
|
126
|
-
</template>
|
|
127
|
-
<template #empty>
|
|
128
|
-
<p style="margin: 0; padding: var(--m-space-8); text-align: center; color: var(--m-color-text-muted)">
|
|
129
|
-
暂无用户数据
|
|
130
|
-
</p>
|
|
131
|
-
</template>
|
|
132
|
-
</MTable>
|
|
133
|
-
</MPageContent>
|
|
134
|
-
</MLayoutContent>
|
|
135
|
-
</MLayout>
|
|
136
|
-
</MLayout>
|
|
137
|
-
</MConfigProvider>
|
|
138
|
-
</template>
|