@morya-ui/mcp 0.3.3 → 0.3.4

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.
@@ -8,26 +8,26 @@ export const pageSnippets = [
8
8
  pageTypes: ['list'],
9
9
  keywords: ['筛选', '搜索', '查询', 'filters', 'filter', 'search', 'keyword', 'reset'],
10
10
  imports: ['MPageFilters', 'MSpace', 'MInput', 'MSelect', 'MButton'],
11
- scriptSetup: `const keyword = ref('')
12
- const status = ref<string | undefined>()
13
- const statusOptions = [
14
- { label: '全部', value: '' },
15
- { label: '启用', value: 'active' },
16
- { label: '停用', value: 'inactive' },
11
+ scriptSetup: `const keyword = ref('')
12
+ const status = ref<string | undefined>()
13
+ const statusOptions = [
14
+ { label: '全部', value: '' },
15
+ { label: '启用', value: 'active' },
16
+ { label: '停用', value: 'inactive' },
17
17
  ]`,
18
- template: `<MPageFilters aria-label="筛选" variant="filled">
19
- <MSpace wrap>
20
- <MInput v-model="keyword" placeholder="搜索名称" clearable style="width: 14rem" />
21
- <MSelect
22
- v-model="status"
23
- :options="statusOptions"
24
- placeholder="状态"
25
- clearable
26
- style="width: 10rem"
27
- />
28
- <MButton severity="secondary">查询</MButton>
29
- <MButton severity="secondary" text>重置</MButton>
30
- </MSpace>
18
+ template: `<MPageFilters aria-label="筛选" variant="filled">
19
+ <MSpace wrap>
20
+ <MInput v-model="keyword" placeholder="搜索名称" clearable style="width: 14rem" />
21
+ <MSelect
22
+ v-model="status"
23
+ :options="statusOptions"
24
+ placeholder="状态"
25
+ clearable
26
+ style="width: 10rem"
27
+ />
28
+ <MButton severity="secondary">查询</MButton>
29
+ <MButton severity="secondary" text>重置</MButton>
30
+ </MSpace>
31
31
  </MPageFilters>`,
32
32
  rules: ['放在 MPageHeader 之后、表格之前', 'viewport 内仅一个 primary(通常在 Header)', '不要外包 MCard'],
33
33
  rulesEn: ['Place after MPageHeader and before the table', 'Keep one primary in the viewport (usually in Header)', 'Do not wrap with MCard'],
@@ -43,31 +43,31 @@ const statusOptions = [
43
43
  pageTypes: ['list'],
44
44
  keywords: ['折叠', '高级筛选', 'collapse', 'advanced', 'expand', 'filter'],
45
45
  imports: ['MPageFilters', 'MSpace', 'MInput', 'MSelect', 'MButton'],
46
- scriptSetup: `const filtersExpanded = ref(false)
47
- const keyword = ref('')
46
+ scriptSetup: `const filtersExpanded = ref(false)
47
+ const keyword = ref('')
48
48
  const department = ref<string | null>(null)`,
49
- template: `<MPageFilters
50
- v-model:expanded="filtersExpanded"
51
- aria-label="筛选"
52
- variant="filled"
53
- collapsible
54
- >
55
- <MSpace wrap>
56
- <MInput v-model="keyword" placeholder="搜索名称" clearable style="width: 14rem" />
57
- <MButton severity="secondary">查询</MButton>
58
- <MButton severity="secondary" text>重置</MButton>
59
- </MSpace>
60
- <template #advanced>
61
- <MSpace wrap>
62
- <MSelect
63
- v-model="department"
64
- :options="[{ label: '研发', value: '研发' }, { label: '运营', value: '运营' }]"
65
- placeholder="部门"
66
- clearable
67
- style="width: 10rem"
68
- />
69
- </MSpace>
70
- </template>
49
+ template: `<MPageFilters
50
+ v-model:expanded="filtersExpanded"
51
+ aria-label="筛选"
52
+ variant="filled"
53
+ collapsible
54
+ >
55
+ <MSpace wrap>
56
+ <MInput v-model="keyword" placeholder="搜索名称" clearable style="width: 14rem" />
57
+ <MButton severity="secondary">查询</MButton>
58
+ <MButton severity="secondary" text>重置</MButton>
59
+ </MSpace>
60
+ <template #advanced>
61
+ <MSpace wrap>
62
+ <MSelect
63
+ v-model="department"
64
+ :options="[{ label: '研发', value: '研发' }, { label: '运营', value: '运营' }]"
65
+ placeholder="部门"
66
+ clearable
67
+ style="width: 10rem"
68
+ />
69
+ </MSpace>
70
+ </template>
71
71
  </MPageFilters>`,
72
72
  rules: ['常用条件放 default,次要条件放 #advanced', '查询/重置保持 secondary'],
73
73
  rulesEn: ['Keep primary filters in default; secondary filters in #advanced', 'Query/reset stay secondary'],
@@ -83,16 +83,16 @@ const department = ref<string | null>(null)`,
83
83
  pageTypes: ['list'],
84
84
  keywords: ['已选', 'chip', 'tag', 'active', 'clear', '筛选'],
85
85
  imports: ['MPageFilterChips', 'MTag'],
86
- template: `<MPageFilterChips label="已选" aria-label="已选筛选">
87
- <MTag
88
- v-for="item in activeFilters"
89
- :key="item.key"
90
- :value="item.label"
91
- size="small"
92
- bordered
93
- closable
94
- @close="clearFilter(item.key)"
95
- />
86
+ template: `<MPageFilterChips label="已选" aria-label="已选筛选">
87
+ <MTag
88
+ v-for="item in activeFilters"
89
+ :key="item.key"
90
+ :value="item.label"
91
+ size="small"
92
+ bordered
93
+ closable
94
+ @close="clearFilter(item.key)"
95
+ />
96
96
  </MPageFilterChips>`,
97
97
  rules: ['放在 MPageFilters 之后、表格之前', '用业务 computed 生成 activeFilters'],
98
98
  rulesEn: ['Place after MPageFilters and before the table', 'Derive activeFilters from filter state'],
@@ -108,10 +108,10 @@ const department = ref<string | null>(null)`,
108
108
  pageTypes: ['list'],
109
109
  keywords: ['页头', '标题', '新建', 'header', 'title', 'create', 'actions'],
110
110
  imports: ['MPageHeader', 'MButton'],
111
- template: `<MPageHeader title="用户管理" description="维护账号、角色与权限。">
112
- <template #actions>
113
- <MButton severity="primary">新建用户</MButton>
114
- </template>
111
+ template: `<MPageHeader title="用户管理" description="维护账号、角色与权限。">
112
+ <template #actions>
113
+ <MButton severity="primary">新建用户</MButton>
114
+ </template>
115
115
  </MPageHeader>`,
116
116
  rules: ['页级标题用 MPageHeader,不要用 MPageToolbar 当第二页头', '主操作放 #actions'],
117
117
  rulesEn: ['Use MPageHeader for page identity; do not use MPageToolbar as a second page title', 'Put primary actions in #actions'],
@@ -127,12 +127,12 @@ const department = ref<string | null>(null)`,
127
127
  pageTypes: ['list'],
128
128
  keywords: ['批量', '已选', 'toolbar', 'batch', 'export', 'delete'],
129
129
  imports: ['MPageToolbar', 'MButton'],
130
- template: `<MPageToolbar>
131
- <span style="color:var(--m-color-text-muted);font-size:var(--m-font-size-sm)">已选 0 项</span>
132
- <template #actions>
133
- <MButton severity="secondary" text>导出</MButton>
134
- <MButton severity="danger" text>删除</MButton>
135
- </template>
130
+ template: `<MPageToolbar>
131
+ <span style="color:var(--m-color-text-muted);font-size:var(--m-font-size-sm)">已选 0 项</span>
132
+ <template #actions>
133
+ <MButton severity="secondary" text>导出</MButton>
134
+ <MButton severity="danger" text>删除</MButton>
135
+ </template>
136
136
  </MPageToolbar>`,
137
137
  rules: ['左侧用 default 插槽展示已选数量', '批量操作用 text/outlined,danger 仅 destructive'],
138
138
  rulesEn: ['Use the default slot for selection count', 'Batch actions use text/outlined; danger only for destructive ops'],
@@ -143,46 +143,75 @@ const department = ref<string | null>(null)`,
143
143
  id: 'list-table',
144
144
  title: '列表页表格',
145
145
  titleEn: 'List page table',
146
- description: '标准 MTable,直接放在 MPageContent 内,不额外包 Card。',
147
- descriptionEn: 'Standard MTable placed directly in MPageContent without an extra Card wrapper.',
146
+ description: '标准 MTable,直接放在 MPageContent 内。全视口主列表可再加 fill(表体滚、分页贴底);嵌入/短页不要 fill。',
147
+ descriptionEn: 'Standard MTable in MPageContent. Add fill only for full-viewport main lists; skip fill for embedded/short pages.',
148
148
  pageTypes: ['list'],
149
- keywords: ['表格', 'table', 'pagination', 'paginator', 'empty', 'columns', 'rows'],
149
+ keywords: [
150
+ '表格',
151
+ 'table',
152
+ 'pagination',
153
+ 'paginator',
154
+ 'empty',
155
+ 'columns',
156
+ 'rows',
157
+ 'fill',
158
+ '撑满',
159
+ '分页',
160
+ ],
150
161
  imports: ['MTable', 'MEmpty', 'MButton'],
151
- scriptSetup: `const columns = [
152
- { key: 'name', label: '名称' },
153
- { key: 'status', label: '状态' },
154
- { key: 'updatedAt', label: '更新时间' },
155
- { key: 'actions', label: '操作', width: 128 },
156
- ]
157
- const rows = ref<Record<string, unknown>[]>([])
162
+ scriptSetup: `const columns = [
163
+ { key: 'name', label: '名称' },
164
+ { key: 'status', label: '状态' },
165
+ { key: 'updatedAt', label: '更新时间' },
166
+ { key: 'actions', label: '操作', width: 128 },
167
+ ]
168
+ const rows = ref<Record<string, unknown>[]>([])
158
169
  const loading = ref(false)`,
159
- template: `<MTable
160
- :columns="columns"
161
- :rows="rows"
162
- :loading="loading"
163
- paginator
164
- :rows-per-page="10"
165
- striped
166
- bordered
167
- row-key="id"
168
- aria-label="数据列表"
169
- >
170
- <template #empty>
171
- <MEmpty
172
- title="还没有数据"
173
- description="创建第一条记录后,这里会列出结果。"
174
- icon="inbox"
175
- >
176
- <template #extra>
177
- <MButton severity="primary">新建</MButton>
178
- </template>
179
- </MEmpty>
180
- </template>
170
+ template: `<!-- 全视口主列表再加 fill;嵌入/短页去掉 fill -->
171
+ <MTable
172
+ :columns="columns"
173
+ :rows="rows"
174
+ :loading="loading"
175
+ fill
176
+ paginator
177
+ :rows-per-page="10"
178
+ striped
179
+ bordered
180
+ row-key="id"
181
+ aria-label="数据列表"
182
+ >
183
+ <template #empty>
184
+ <MEmpty
185
+ title="还没有数据"
186
+ description="创建第一条记录后,这里会列出结果。"
187
+ icon="inbox"
188
+ >
189
+ <template #extra>
190
+ <MButton severity="primary">新建</MButton>
191
+ </template>
192
+ </MEmpty>
193
+ </template>
181
194
  </MTable>`,
182
- rules: ['表格直接放在 MPageContent 内', '空态用 MEmpty,不要留空白或单行灰字'],
183
- rulesEn: ['Place the table directly in MPageContent', 'Use MEmpty for zero-data states, not a blank or muted sentence'],
184
- avoid: ['不要用 MCard 包裹 bordered MTable'],
185
- avoidEn: ['Do not wrap a bordered MTable with MCard'],
195
+ rules: [
196
+ '先判断是否适合 fill:全视口后台主列表 + 表格是主任务 → MPageContent fill + MTable fill',
197
+ '嵌入表、短页、整页文档滚动 → 不要 fill,内容高度即可',
198
+ '表格直接放在 MPageContent 内;空态用 MEmpty',
199
+ ],
200
+ rulesEn: [
201
+ 'Decide fill first: full-viewport admin main list → MPageContent fill + MTable fill',
202
+ 'Embedded / short / document-scroll pages → skip fill',
203
+ 'Place the table directly in MPageContent; use MEmpty for zero-data states',
204
+ ],
205
+ avoid: [
206
+ '不要用 MCard 包裹 bordered MTable',
207
+ '不要对嵌入/短页硬套 fill',
208
+ '适合 fill 时不要手写 min-height / calc',
209
+ ],
210
+ avoidEn: [
211
+ 'Do not wrap a bordered MTable with MCard',
212
+ 'Do not force fill on embedded or short pages',
213
+ 'Do not hand-write min-height / calc when fill is appropriate',
214
+ ],
186
215
  },
187
216
  {
188
217
  id: 'list-row-actions',
@@ -193,11 +222,11 @@ const loading = ref(false)`,
193
222
  pageTypes: ['list'],
194
223
  keywords: ['行操作', '编辑', '删除', 'actions', 'row', 'cell'],
195
224
  imports: ['MSpace', 'MButton'],
196
- template: `<template #cell-actions>
197
- <MSpace>
198
- <MButton severity="secondary" size="small" text>编辑</MButton>
199
- <MButton severity="danger" size="small" text>删除</MButton>
200
- </MSpace>
225
+ template: `<template #cell-actions>
226
+ <MSpace>
227
+ <MButton severity="secondary" size="small" text>编辑</MButton>
228
+ <MButton severity="danger" size="small" text>删除</MButton>
229
+ </MSpace>
201
230
  </template>`,
202
231
  rules: ['行内操作用 size="small" + text/outlined,避免一排实心按钮', '危险操作使用 severity="danger" 并配合确认弹窗'],
203
232
  rulesEn: ['Use size="small" with text/outlined row actions', 'Use severity="danger" with confirmation for destructive actions'],
@@ -213,11 +242,11 @@ const loading = ref(false)`,
213
242
  pageTypes: ['list'],
214
243
  keywords: ['分类', '标签', '可关闭', 'chip', 'category', 'tag-only'],
215
244
  imports: ['MTag'],
216
- template: `<template #cell-category="{ value }">
217
- <MTag
218
- :value="String(value ?? '')"
219
- severity="info"
220
- />
245
+ template: `<template #cell-category="{ value }">
246
+ <MTag
247
+ :value="String(value ?? '')"
248
+ severity="info"
249
+ />
221
250
  </template>`,
222
251
  rules: ['分类/强调态用 MTag;行内业务状态用 MStatus(list-status-dot)', '不要用 Button 颜色表达状态'],
223
252
  rulesEn: ['Use MTag for categories; use MStatus for business status (list-status-dot)', 'Do not use Button colors for status'],
@@ -233,11 +262,11 @@ const loading = ref(false)`,
233
262
  pageTypes: ['list'],
234
263
  keywords: ['状态', 'status', 'dot', 'cell-status', '在线', '启用', '停用', '业务状态'],
235
264
  imports: ['MStatus'],
236
- template: `<template #cell-status="{ value }">
237
- <MStatus
238
- :label="value === 'active' || value === 'online' ? '启用' : '停用'"
239
- :severity="value === 'active' || value === 'online' ? 'success' : 'secondary'"
240
- />
265
+ template: `<template #cell-status="{ value }">
266
+ <MStatus
267
+ :label="value === 'active' || value === 'online' ? '启用' : '停用'"
268
+ :severity="value === 'active' || value === 'online' ? 'success' : 'secondary'"
269
+ />
241
270
  </template>`,
242
271
  rules: ['行内轻量业务状态优先 MStatus', '不要用 Button 颜色表达状态'],
243
272
  rulesEn: ['Prefer MStatus for lightweight inline business status', 'Do not use Button colors for status'],
@@ -253,15 +282,15 @@ const loading = ref(false)`,
253
282
  pageTypes: ['list', 'common'],
254
283
  keywords: ['空状态', '无数据', 'empty', 'zero state', 'no data'],
255
284
  imports: ['MEmpty', 'MButton'],
256
- template: `<MEmpty
257
- title="还没有数据"
258
- description="创建第一条记录后即可在此查看。"
259
- icon="database"
260
- >
261
- <template #extra>
262
- <MButton label="新建" />
263
- <MButton label="导入" severity="secondary" text />
264
- </template>
285
+ template: `<MEmpty
286
+ title="还没有数据"
287
+ description="创建第一条记录后即可在此查看。"
288
+ icon="database"
289
+ >
290
+ <template #extra>
291
+ <MButton label="新建" />
292
+ <MButton label="导入" severity="secondary" text />
293
+ </template>
265
294
  </MEmpty>`,
266
295
  rules: ['正常无数据用 MEmpty,不要用错误色', '主 CTA 用 primary,次动作用 text/secondary'],
267
296
  rulesEn: ['Use MEmpty for normal emptiness, not error colors', 'Primary CTA + secondary/text for lesser actions'],
@@ -277,11 +306,11 @@ const loading = ref(false)`,
277
306
  pageTypes: ['common'],
278
307
  keywords: ['结果', '成功', '失败', '404', '403', 'result', 'success', 'error'],
279
308
  imports: ['MResult', 'MButton'],
280
- template: `<MResult status="success" description="订单已创建,可在列表中查看详情。">
281
- <template #extra>
282
- <MButton label="查看订单" />
283
- <MButton label="返回列表" severity="secondary" text />
284
- </template>
309
+ template: `<MResult status="success" description="订单已创建,可在列表中查看详情。">
310
+ <template #extra>
311
+ <MButton label="查看订单" />
312
+ <MButton label="返回列表" severity="secondary" text />
313
+ </template>
285
314
  </MResult>`,
286
315
  rules: ['流程终点用 MResult', '提供明确下一步操作'],
287
316
  rulesEn: ['Use MResult for terminal outcomes', 'Provide clear next-step actions'],
@@ -312,15 +341,15 @@ const loading = ref(false)`,
312
341
  pageTypes: ['form'],
313
342
  keywords: ['表单', 'form', 'fields', 'formitem'],
314
343
  imports: ['MPageSection', 'MForm', 'MFormItem', 'MInput'],
315
- scriptSetup: `const model = reactive({ name: '' })
344
+ scriptSetup: `const model = reactive({ name: '' })
316
345
  const submitting = ref(false)`,
317
- template: `<MPageSection variant="form">
318
- <MForm @submit.prevent="onSubmit">
319
- <MFormItem label="姓名" name="name" required>
320
- <MInput v-model="model.name" placeholder="请输入姓名" fluid />
321
- </MFormItem>
322
- <!-- 更多字段 -->
323
- </MForm>
346
+ template: `<MPageSection variant="form">
347
+ <MForm @submit.prevent="onSubmit">
348
+ <MFormItem label="姓名" name="name" required>
349
+ <MInput v-model="model.name" placeholder="请输入姓名" fluid />
350
+ </MFormItem>
351
+ <!-- 更多字段 -->
352
+ </MForm>
324
353
  </MPageSection>`,
325
354
  rules: ['字段用 MFormItem + fluid 控件', '表单表面由 MPageSection 提供,不要重复 MCard'],
326
355
  rulesEn: ['Use MFormItem with fluid controls', 'Let MPageSection provide the surface; do not duplicate MCard'],
@@ -336,11 +365,11 @@ const submitting = ref(false)`,
336
365
  pageTypes: ['form'],
337
366
  keywords: ['保存', '取消', 'submit', 'actions', 'footer'],
338
367
  imports: ['MPageSection', 'MSpace', 'MButton'],
339
- template: `<MPageSection variant="actions">
340
- <MSpace>
341
- <MButton native-type="submit" severity="primary" :loading="submitting">保存</MButton>
342
- <MButton severity="secondary">取消</MButton>
343
- </MSpace>
368
+ template: `<MPageSection variant="actions">
369
+ <MSpace>
370
+ <MButton native-type="submit" severity="primary" :loading="submitting">保存</MButton>
371
+ <MButton severity="secondary">取消</MButton>
372
+ </MSpace>
344
373
  </MPageSection>`,
345
374
  rules: ['提交按钮在前,取消 secondary', '保存中传 loading 防重复提交'],
346
375
  rulesEn: ['Submit first, cancel secondary', 'Pass loading while saving to prevent duplicate submits'],
@@ -356,21 +385,21 @@ const submitting = ref(false)`,
356
385
  pageTypes: ['dashboard'],
357
386
  keywords: ['kpi', '指标', 'stat', 'grid', 'metrics'],
358
387
  imports: ['MGrid', 'MGridItem', 'MPageStat'],
359
- scriptSetup: `const metrics = ref([
360
- { label: '总用户', value: '12,480', trend: '+8.2%', trendDirection: 'up' as const, trendLabel: '较上月', icon: 'users' },
361
- { label: '今日活跃', value: '1,926', trend: '+3.1%', trendDirection: 'up' as const, trendLabel: '较昨日', icon: 'activity' },
388
+ scriptSetup: `const metrics = ref([
389
+ { label: '总用户', value: '12,480', trend: '+8.2%', trendDirection: 'up' as const, trendLabel: '较上月', icon: 'users' },
390
+ { label: '今日活跃', value: '1,926', trend: '+3.1%', trendDirection: 'up' as const, trendLabel: '较昨日', icon: 'activity' },
362
391
  ])`,
363
- template: `<MGrid :cols="4" :x-gap="16" :y-gap="16" responsive="screen">
364
- <MGridItem v-for="metric in metrics" :key="metric.label" :span="1">
365
- <MPageStat
366
- :label="metric.label"
367
- :value="metric.value"
368
- :trend="metric.trend"
369
- :trend-direction="metric.trendDirection"
370
- :trend-label="metric.trendLabel"
371
- :icon="metric.icon"
372
- />
373
- </MGridItem>
392
+ template: `<MGrid :cols="4" :x-gap="16" :y-gap="16" responsive="screen">
393
+ <MGridItem v-for="metric in metrics" :key="metric.label" :span="1">
394
+ <MPageStat
395
+ :label="metric.label"
396
+ :value="metric.value"
397
+ :trend="metric.trend"
398
+ :trend-direction="metric.trendDirection"
399
+ :trend-label="metric.trendLabel"
400
+ :icon="metric.icon"
401
+ />
402
+ </MGridItem>
374
403
  </MGrid>`,
375
404
  rules: ['KPI 用 MPageStat,不要每页自定义 stat CSS', 'responsive="screen" 便于窄屏降列'],
376
405
  rulesEn: ['Use MPageStat for KPIs', 'Use responsive="screen" for narrow layouts'],
@@ -386,14 +415,14 @@ const submitting = ref(false)`,
386
415
  pageTypes: ['dashboard'],
387
416
  keywords: ['chart', '图表', 'placeholder', 'card', 'trend'],
388
417
  imports: ['MCard', 'MEmpty', 'MSkeleton'],
389
- template: `<MCard title="趋势概览" shadow="always">
390
- <MSkeleton v-if="loading" height="8rem" />
391
- <MEmpty
392
- v-else
393
- aria-label="图表占位"
394
- title="暂无图表数据"
395
- description="图表区域(接入 ECharts / 业务组件)"
396
- />
418
+ template: `<MCard title="趋势概览" shadow="always">
419
+ <MSkeleton v-if="loading" height="8rem" />
420
+ <MEmpty
421
+ v-else
422
+ aria-label="图表占位"
423
+ title="暂无图表数据"
424
+ description="图表区域(接入 ECharts / 业务组件)"
425
+ />
397
426
  </MCard>`,
398
427
  rules: ['图表区适合 MCard,因为需要 card 标题', '加载中用 MSkeleton'],
399
428
  rulesEn: ['Charts belong in MCard when a card title is needed', 'Use MSkeleton while loading'],
@@ -409,18 +438,18 @@ const submitting = ref(false)`,
409
438
  pageTypes: ['dashboard'],
410
439
  keywords: ['recent', '最近', 'table', 'card', 'list'],
411
440
  imports: ['MCard', 'MTable', 'MStatus'],
412
- scriptSetup: `const recentColumns = [
413
- { key: 'id', label: '工单号', width: 96 },
414
- { key: 'title', label: '标题' },
415
- { key: 'status', label: '状态', width: 110 },
416
- ]
441
+ scriptSetup: `const recentColumns = [
442
+ { key: 'id', label: '工单号', width: 96 },
443
+ { key: 'title', label: '标题' },
444
+ { key: 'status', label: '状态', width: 110 },
445
+ ]
417
446
  const recentRows = ref<Record<string, unknown>[]>([])`,
418
- template: `<MCard title="最近工单">
419
- <MTable :columns="recentColumns" :rows="recentRows" size="small" :paginator="false" bordered row-key="id">
420
- <template #cell-status="{ value }">
421
- <MStatus :label="String(value ?? '')" severity="secondary" />
422
- </template>
423
- </MTable>
447
+ template: `<MCard title="最近工单">
448
+ <MTable :columns="recentColumns" :rows="recentRows" size="small" :paginator="false" bordered row-key="id">
449
+ <template #cell-status="{ value }">
450
+ <MStatus :label="String(value ?? '')" severity="secondary" />
451
+ </template>
452
+ </MTable>
424
453
  </MCard>`,
425
454
  rules: ['明细列表放 MCard 内合理', 'size="small" 适合卡片内表格', '行内业务状态用 MStatus'],
426
455
  rulesEn: ['Detail lists inside MCard are appropriate', 'Use size="small" for in-card tables', 'Use MStatus for row business status'],
@@ -436,10 +465,10 @@ const recentRows = ref<Record<string, unknown>[]>([])`,
436
465
  pageTypes: ['list', 'common'],
437
466
  keywords: ['page content', 'stack', 'layout content', '容器'],
438
467
  imports: ['MPageContent'],
439
- template: `<MLayoutContent>
440
- <MPageContent>
441
- <!-- MPageFilters → MPageToolbar → MTable -->
442
- </MPageContent>
468
+ template: `<MLayoutContent>
469
+ <MPageContent>
470
+ <!-- MPageFilters → MPageToolbar → MTable -->
471
+ </MPageContent>
443
472
  </MLayoutContent>`,
444
473
  rules: ['所有列表区块放在 MPageContent 内', '区块顺序:筛选 → 工具栏 → 表格'],
445
474
  rulesEn: ['Keep all list sections inside MPageContent', 'Order: filters → toolbar → table'],
@@ -455,10 +484,10 @@ const recentRows = ref<Record<string, unknown>[]>([])`,
455
484
  pageTypes: ['form', 'common'],
456
485
  keywords: ['narrow', 'form content', 'max-width'],
457
486
  imports: ['MPageContent'],
458
- template: `<MLayoutContent>
459
- <MPageContent width="narrow">
460
- <!-- MPageHeader → MPageSection form → actions -->
461
- </MPageContent>
487
+ template: `<MLayoutContent>
488
+ <MPageContent width="narrow">
489
+ <!-- MPageHeader → MPageSection form → actions -->
490
+ </MPageContent>
462
491
  </MLayoutContent>`,
463
492
  rules: ['表单页使用 width="narrow"', '不要手写 max-width CSS'],
464
493
  rulesEn: ['Use width="narrow" on form pages', 'Do not hand-write max-width CSS'],
@@ -474,14 +503,14 @@ const recentRows = ref<Record<string, unknown>[]>([])`,
474
503
  pageTypes: ['detail'],
475
504
  keywords: ['detail', '详情', 'edit', 'header'],
476
505
  imports: ['MPageHeader', 'MButton', 'MStatus', 'MSpace'],
477
- template: `<MPageHeader title="示例资源" description="查看摘要与属性。">
478
- <template #actions>
479
- <MSpace>
480
- <MStatus label="正常" severity="success" />
481
- <MButton severity="primary">编辑</MButton>
482
- <MButton severity="danger" text>删除</MButton>
483
- </MSpace>
484
- </template>
506
+ template: `<MPageHeader title="示例资源" description="查看摘要与属性。">
507
+ <template #actions>
508
+ <MSpace>
509
+ <MStatus label="正常" severity="success" />
510
+ <MButton severity="primary">编辑</MButton>
511
+ <MButton severity="danger" text>删除</MButton>
512
+ </MSpace>
513
+ </template>
485
514
  </MPageHeader>`,
486
515
  rules: ['状态用 MStatus 放在 actions 区', '编辑为 primary,删除用 danger text'],
487
516
  rulesEn: ['Use MStatus in the actions area', 'Edit is primary; delete uses danger text'],
@@ -507,29 +536,29 @@ const recentRows = ref<Record<string, unknown>[]>([])`,
507
536
  'MConfigProvider',
508
537
  'zhCN',
509
538
  ],
510
- template: `<MConfigProvider :locale="zhCN">
511
- <MLayout fill-viewport has-sider>
512
- <MLayoutSider v-model:collapsed="siderCollapsed" bordered :collapsed-width="72">
513
- <MMenu
514
- :model="[
515
- { key: 'users', label: '用户管理', icon: 'user', to: '/users' },
516
- { key: 'roles', label: '角色管理', icon: 'shield', to: '/roles' },
517
- ]"
518
- :collapsed="siderCollapsed"
519
- :collapsed-width="72"
520
- />
521
- </MLayoutSider>
522
- <MLayout>
523
- <MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
524
- <MBreadcrumb :model="[{ label: '首页', to: '/' }, { label: '当前页' }]" />
525
- </MLayoutHeader>
526
- <MLayoutContent>
527
- <MPageContent>
528
- <!-- page sections -->
529
- </MPageContent>
530
- </MLayoutContent>
531
- </MLayout>
532
- </MLayout>
539
+ template: `<MConfigProvider :locale="zhCN">
540
+ <MLayout fill-viewport has-sider>
541
+ <MLayoutSider v-model:collapsed="siderCollapsed" bordered :collapsed-width="72">
542
+ <MMenu
543
+ :model="[
544
+ { key: 'users', label: '用户管理', icon: 'user', to: '/users' },
545
+ { key: 'roles', label: '角色管理', icon: 'shield', to: '/roles' },
546
+ ]"
547
+ :collapsed="siderCollapsed"
548
+ :collapsed-width="72"
549
+ />
550
+ </MLayoutSider>
551
+ <MLayout>
552
+ <MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
553
+ <MBreadcrumb :model="[{ label: '首页', to: '/' }, { label: '当前页' }]" />
554
+ </MLayoutHeader>
555
+ <MLayoutContent>
556
+ <MPageContent>
557
+ <!-- page sections -->
558
+ </MPageContent>
559
+ </MLayoutContent>
560
+ </MLayout>
561
+ </MLayout>
533
562
  </MConfigProvider>`,
534
563
  rules: [
535
564
  '根布局用 fillViewport',
@@ -562,19 +591,19 @@ const recentRows = ref<Record<string, unknown>[]>([])`,
562
591
  'log',
563
592
  ],
564
593
  imports: ['MScrollbar', 'MCard'],
565
- template: `<MCard title="活动日志">
566
- <MScrollbar max-height="16rem">
567
- <ul style="margin:0;padding:0;list-style:none">
568
- <li v-for="item in logLines" :key="item.id" style="padding:var(--m-space-2) 0;border-bottom:1px solid var(--m-color-border)">
569
- {{ item.text }}
570
- </li>
571
- </ul>
572
- </MScrollbar>
594
+ template: `<MCard title="活动日志">
595
+ <MScrollbar max-height="16rem">
596
+ <ul style="margin:0;padding:0;list-style:none">
597
+ <li v-for="item in logLines" :key="item.id" style="padding:var(--m-space-2) 0;border-bottom:1px solid var(--m-color-border)">
598
+ {{ item.text }}
599
+ </li>
600
+ </ul>
601
+ </MScrollbar>
573
602
  </MCard>`,
574
- scriptSetup: `const logLines = [
575
- { id: '1', text: '用户 admin 登录成功' },
576
- { id: '2', text: '导出任务已完成' },
577
- { id: '3', text: '配置已保存' },
603
+ scriptSetup: `const logLines = [
604
+ { id: '1', text: '用户 admin 登录成功' },
605
+ { id: '2', text: '导出任务已完成' },
606
+ { id: '3', text: '配置已保存' },
578
607
  ]`,
579
608
  rules: [
580
609
  '整页主滚动推荐 MLayout fillViewport',