@xmszm/core 0.0.1 → 0.0.3
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 +187 -0
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +1431 -1170
- package/dist/plugin/vite/initRouteMeta.cjs +1 -0
- package/dist/plugin/vite/initRouteMeta.mjs +13 -0
- package/dist/style.css +1 -1
- package/docs/.vitepress/config.mjs +91 -0
- package/docs/components/config-options.md +125 -0
- package/docs/components/dataform.md +176 -23
- package/docs/components/datatable.md +58 -39
- package/docs/components/dialog.md +158 -19
- package/docs/components/options.md +44 -15
- package/docs/components/query.md +68 -14
- package/docs/components/utils.md +124 -16
- package/docs/guide/changelog.md +81 -0
- package/docs/guide/config.md +415 -0
- package/docs/guide/demo.md +2 -2
- package/docs/guide/local-development.md +109 -0
- package/docs/guide/quickstart.md +40 -11
- package/docs/index.md +3 -3
- package/docs/usage.md +30 -6
- package/examples/README.md +46 -0
- package/examples/index.html +14 -0
- package/examples/package.json +25 -0
- package/examples/pnpm-lock.yaml +1569 -0
- package/examples/pnpm-workspace.yaml +3 -0
- package/examples/src/AdminSystem.vue +870 -0
- package/examples/src/App.vue +330 -0
- package/examples/src/Introduction.vue +307 -0
- package/examples/src/main.js +22 -0
- package/examples/src/utils/permission.js +16 -0
- package/examples/src/utils/request.js +10 -0
- package/examples/vite.config.js +41 -0
- package/package.json +13 -4
- package/src/dialog/commonDialog.tsx +285 -0
- package/src/dialog/useCommonDialog.ts +41 -0
- package/src/dialog/utils/{dialog.js → dialog.ts} +2 -0
- package/src/directives/auto-register.ts +57 -0
- package/src/directives/permission.ts +67 -0
- package/src/enum/sort.tsx +45 -0
- package/src/form/DataForm.vue +34 -52
- package/src/index.ts +58 -0
- package/src/list/{useList.jsx → useList.tsx} +49 -14
- package/src/options/{Options.jsx → Options.tsx} +86 -72
- package/src/options/defaultOptions.tsx +656 -0
- package/src/plugin/index.ts +20 -0
- package/src/query/CommonQuery.vue +65 -90
- package/src/table/DataTable.vue +82 -95
- package/src/table/opr/{DataColumnCollet.jsx → DataColumnCollet.tsx} +18 -8
- package/src/table/opr/useDataColumn.tsx +226 -0
- package/src/table/opr/{useDataColumnButton.jsx → useDataColumnButton.tsx} +13 -6
- package/src/table/opr/{useDataColumnPop.jsx → useDataColumnPop.tsx} +13 -5
- package/src/table/opr/useQRCode.ts +40 -0
- package/src/utils/{array.js → array.ts} +4 -6
- package/src/utils/config.ts +192 -0
- package/src/utils/dialog.ts +110 -0
- package/src/utils/{object.js → object.ts} +1 -0
- package/src/utils/upload.ts +53 -0
- package/types/auto-imports.d.ts +78 -0
- package/types/components.d.ts +402 -0
- package/types/index.d.ts +145 -7
- package/types/plugin/vite/initRouteMeta.d.ts +23 -0
- package/types/src.d.ts +55 -0
- package/types/vue-shim.d.ts +9 -0
- package/examples/demo.vue +0 -224
- package/src/dialog/commonDialog.jsx +0 -230
- package/src/enum/sort.jsx +0 -31
- package/src/index.js +0 -46
- package/src/options/defaultOptions.jsx +0 -580
- package/src/table/opr/useDataColumn.jsx +0 -196
- package/src/utils/upload.js +0 -46
- /package/src/enum/{options.js → options.ts} +0 -0
- /package/src/plugin/vite/{initRouteMeta.js → initRouteMeta.ts} +0 -0
- /package/src/store/utils/{index.js → index.ts} +0 -0
- /package/src/table/utils/{ellipsis.js → ellipsis.ts} +0 -0
- /package/src/utils/{auth.js → auth.ts} +0 -0
- /package/src/utils/{time.js → time.ts} +0 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
<script setup lang="jsx">
|
|
2
|
+
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
|
|
3
|
+
import { NButton, NCard, NSpace, NLayout, NLayoutHeader, NLayoutContent } from 'naive-ui'
|
|
4
|
+
import {
|
|
5
|
+
commonDialogMethod,
|
|
6
|
+
CommonQuery,
|
|
7
|
+
createActionColumnJsx,
|
|
8
|
+
DataTable,
|
|
9
|
+
} from '@xmszm/core'
|
|
10
|
+
import '@xmszm/core/dist/style.css'
|
|
11
|
+
import Introduction from './Introduction.vue'
|
|
12
|
+
import AdminSystem from './AdminSystem.vue'
|
|
13
|
+
|
|
14
|
+
// 从 localStorage 读取保存的视图,如果没有则默认为 'introduction'
|
|
15
|
+
const getInitialView = () => {
|
|
16
|
+
const saved = localStorage.getItem('core-app-view')
|
|
17
|
+
return saved || 'introduction'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const currentView = ref(getInitialView())
|
|
21
|
+
|
|
22
|
+
// 切换视图时保存到 localStorage
|
|
23
|
+
const switchView = (view) => {
|
|
24
|
+
currentView.value = view
|
|
25
|
+
localStorage.setItem('core-app-view', view)
|
|
26
|
+
// 如果切换到 demo 视图且数据为空,则加载数据
|
|
27
|
+
if (view === 'demo' && pageState.data.length === 0) {
|
|
28
|
+
pageState.fetchData()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 查询与分页状态(可替换为业务方的 useNaivePage)
|
|
33
|
+
const listQuery = reactive({
|
|
34
|
+
page: 1,
|
|
35
|
+
pageSize: 10,
|
|
36
|
+
desc: true,
|
|
37
|
+
likeQuery: {
|
|
38
|
+
name1: '',
|
|
39
|
+
name2: '',
|
|
40
|
+
name3: '',
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const pageState = reactive({
|
|
45
|
+
data: [],
|
|
46
|
+
itemCount: 0,
|
|
47
|
+
loading: false,
|
|
48
|
+
page: computed(() => listQuery.page),
|
|
49
|
+
pageSize: computed(() => listQuery.pageSize),
|
|
50
|
+
showSizePicker: true,
|
|
51
|
+
pageSizes: [10, 20, 50],
|
|
52
|
+
onUpdatePage: (p) => {
|
|
53
|
+
listQuery.page = p
|
|
54
|
+
pageState.fetchData()
|
|
55
|
+
},
|
|
56
|
+
onUpdatePageSize: (ps) => {
|
|
57
|
+
listQuery.pageSize = ps
|
|
58
|
+
listQuery.page = 1
|
|
59
|
+
pageState.fetchData()
|
|
60
|
+
},
|
|
61
|
+
fetchData: async () => {
|
|
62
|
+
pageState.loading = true
|
|
63
|
+
try {
|
|
64
|
+
// 模拟请求
|
|
65
|
+
const mock = Array.from({ length: 25 }).map((_, i) => ({
|
|
66
|
+
id: i + 1,
|
|
67
|
+
name: `名称-${i + 1}`,
|
|
68
|
+
type: i % 2 ? 'B' : 'A',
|
|
69
|
+
}))
|
|
70
|
+
pageState.itemCount = mock.length
|
|
71
|
+
const start = (listQuery.page - 1) * listQuery.pageSize
|
|
72
|
+
const end = start + listQuery.pageSize
|
|
73
|
+
pageState.data = mock.slice(start, end)
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
pageState.loading = false
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
search: () => {
|
|
80
|
+
listQuery.page = 1
|
|
81
|
+
pageState.fetchData()
|
|
82
|
+
},
|
|
83
|
+
reset: () => {
|
|
84
|
+
listQuery.likeQuery = { name1: '', name2: '', name3: '' }
|
|
85
|
+
listQuery.page = 1
|
|
86
|
+
pageState.fetchData()
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// 查询项
|
|
91
|
+
const keyQuery = [
|
|
92
|
+
{ label: '名称1', key: 'name1', queryType: 'likeQuery' },
|
|
93
|
+
{ label: '名称2', key: 'name2', queryType: 'likeQuery' },
|
|
94
|
+
{ label: '名称3', key: 'name3', queryType: 'likeQuery' },
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
// 表格列与操作列
|
|
98
|
+
const columns = [
|
|
99
|
+
{ title: '名称', key: 'name', width: 160 },
|
|
100
|
+
{ title: '类型', key: 'type', width: 120 },
|
|
101
|
+
]
|
|
102
|
+
const defaultColumns = []
|
|
103
|
+
const selectColumns = { type: 'selection', width: '40px' }
|
|
104
|
+
const opr = createActionColumnJsx([
|
|
105
|
+
{
|
|
106
|
+
label: '编辑',
|
|
107
|
+
type: 'primary',
|
|
108
|
+
onClick: row => onAdd(row, 'edit'),
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
label: '删除',
|
|
112
|
+
type: 'error',
|
|
113
|
+
mode: 'pop',
|
|
114
|
+
onClick: (row) => {
|
|
115
|
+
console.log('删除', row)
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
])
|
|
119
|
+
|
|
120
|
+
// 弹窗新增/编辑
|
|
121
|
+
function onAdd(row = null, mode = 'add') {
|
|
122
|
+
commonDialogMethod({
|
|
123
|
+
title: '示例弹窗',
|
|
124
|
+
mode,
|
|
125
|
+
options: [
|
|
126
|
+
{ key: 'name', label: '名称', way: 'input', required: true },
|
|
127
|
+
{
|
|
128
|
+
key: 'type',
|
|
129
|
+
label: '类型',
|
|
130
|
+
way: 'select',
|
|
131
|
+
options: [
|
|
132
|
+
{ name: '类型A', id: 'A' },
|
|
133
|
+
{ name: '类型B', id: 'B' },
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
valueData: { ...row },
|
|
138
|
+
interfaceFn: async (data, { close }) => {
|
|
139
|
+
console.log('提交数据', data)
|
|
140
|
+
pageState.fetchData()
|
|
141
|
+
close()
|
|
142
|
+
},
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 导出示例
|
|
147
|
+
const exportLoading = reactive({ value: false })
|
|
148
|
+
function onExport() {
|
|
149
|
+
exportLoading.value = true
|
|
150
|
+
setTimeout(() => (exportLoading.value = false), 800)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 监听自定义事件,实现跨组件通信
|
|
154
|
+
const handleViewChange = (e) => {
|
|
155
|
+
if (e.detail && e.detail.view) {
|
|
156
|
+
switchView(e.detail.view)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
onMounted(() => {
|
|
161
|
+
// 如果当前视图是 demo,则加载数据
|
|
162
|
+
if (currentView.value === 'demo') {
|
|
163
|
+
pageState.fetchData()
|
|
164
|
+
}
|
|
165
|
+
// 监听自定义视图切换事件
|
|
166
|
+
window.addEventListener('view-change', handleViewChange)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
// 清理事件监听
|
|
170
|
+
onUnmounted(() => {
|
|
171
|
+
window.removeEventListener('view-change', handleViewChange)
|
|
172
|
+
})
|
|
173
|
+
</script>
|
|
174
|
+
|
|
175
|
+
<template>
|
|
176
|
+
<AdminSystem v-if="currentView === 'admin'" />
|
|
177
|
+
<n-layout v-else class="app-layout">
|
|
178
|
+
<n-layout-header class="app-header" bordered>
|
|
179
|
+
<div class="header-content">
|
|
180
|
+
<h2 class="app-title">@xmszm/core 组件库</h2>
|
|
181
|
+
<n-space>
|
|
182
|
+
<n-button
|
|
183
|
+
type="default"
|
|
184
|
+
tag="a"
|
|
185
|
+
href="/core/"
|
|
186
|
+
target="_self"
|
|
187
|
+
>
|
|
188
|
+
返回文档
|
|
189
|
+
</n-button>
|
|
190
|
+
<n-button
|
|
191
|
+
:type="currentView === 'introduction' ? 'primary' : 'default'"
|
|
192
|
+
@click="switchView('introduction')"
|
|
193
|
+
>
|
|
194
|
+
项目介绍
|
|
195
|
+
</n-button>
|
|
196
|
+
<n-button
|
|
197
|
+
:type="currentView === 'demo' ? 'primary' : 'default'"
|
|
198
|
+
@click="switchView('demo')"
|
|
199
|
+
>
|
|
200
|
+
组件示例
|
|
201
|
+
</n-button>
|
|
202
|
+
<n-button
|
|
203
|
+
:type="currentView === 'admin' ? 'primary' : 'default'"
|
|
204
|
+
@click="switchView('admin')"
|
|
205
|
+
>
|
|
206
|
+
管理后台
|
|
207
|
+
</n-button>
|
|
208
|
+
</n-space>
|
|
209
|
+
</div>
|
|
210
|
+
</n-layout-header>
|
|
211
|
+
<n-layout-content class="app-content">
|
|
212
|
+
<Introduction v-if="currentView === 'introduction'" />
|
|
213
|
+
<div v-else class="page-box">
|
|
214
|
+
<!-- 头部筛选 -->
|
|
215
|
+
<NCard class="page-head">
|
|
216
|
+
<CommonQuery
|
|
217
|
+
:query="listQuery"
|
|
218
|
+
:options="keyQuery"
|
|
219
|
+
@submit="pageState.search()"
|
|
220
|
+
@reset="pageState.reset()"
|
|
221
|
+
/>
|
|
222
|
+
</NCard>
|
|
223
|
+
|
|
224
|
+
<!-- 操作区 -->
|
|
225
|
+
<NSpace justify="space-between">
|
|
226
|
+
<NSpace>
|
|
227
|
+
<NButton type="primary" @click="onAdd()">新增</NButton>
|
|
228
|
+
<NButton type="primary" :loading="exportLoading.value" @click="onExport">
|
|
229
|
+
导出
|
|
230
|
+
</NButton>
|
|
231
|
+
</NSpace>
|
|
232
|
+
</NSpace>
|
|
233
|
+
|
|
234
|
+
<!-- 内容表格区 -->
|
|
235
|
+
<div class="page-main">
|
|
236
|
+
<DataTable
|
|
237
|
+
:data="pageState.data"
|
|
238
|
+
:pagination="pageState"
|
|
239
|
+
:columns="columns"
|
|
240
|
+
:opr-columns="opr"
|
|
241
|
+
:default-columns="defaultColumns"
|
|
242
|
+
:row-key="row => row?.id"
|
|
243
|
+
:select-columns="selectColumns"
|
|
244
|
+
:loading="pageState.loading"
|
|
245
|
+
:flex-height="false"
|
|
246
|
+
/>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
</n-layout-content>
|
|
250
|
+
</n-layout>
|
|
251
|
+
</template>
|
|
252
|
+
|
|
253
|
+
<style scoped lang="less">
|
|
254
|
+
.app-layout {
|
|
255
|
+
height: 100vh;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.app-header {
|
|
259
|
+
padding: 0 24px;
|
|
260
|
+
height: 64px;
|
|
261
|
+
display: flex;
|
|
262
|
+
align-items: center;
|
|
263
|
+
background: #fff;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.header-content {
|
|
267
|
+
width: 100%;
|
|
268
|
+
display: flex;
|
|
269
|
+
justify-content: space-between;
|
|
270
|
+
align-items: center;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.app-title {
|
|
274
|
+
margin: 0;
|
|
275
|
+
font-size: 20px;
|
|
276
|
+
font-weight: 600;
|
|
277
|
+
color: #18a058;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.app-content {
|
|
281
|
+
padding: 0;
|
|
282
|
+
overflow: auto;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.page-head {
|
|
286
|
+
border-radius: 8px;
|
|
287
|
+
background-color: #fff;
|
|
288
|
+
box-sizing: border-box;
|
|
289
|
+
display: flex;
|
|
290
|
+
flex-direction: column;
|
|
291
|
+
row-gap: 20px;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.page-main {
|
|
295
|
+
flex: 0 1 auto;
|
|
296
|
+
background-color: #fff;
|
|
297
|
+
border-radius: 8px;
|
|
298
|
+
padding: 20px;
|
|
299
|
+
box-sizing: border-box;
|
|
300
|
+
display: flex;
|
|
301
|
+
height: 100%;
|
|
302
|
+
flex-direction: column;
|
|
303
|
+
row-gap: 10px;
|
|
304
|
+
|
|
305
|
+
.n-data-table {
|
|
306
|
+
.n-data-table-th {
|
|
307
|
+
background-color: #f7f8fa;
|
|
308
|
+
border-right: 1px solid var(--n-merged-border-color);
|
|
309
|
+
white-space: break-spaces;
|
|
310
|
+
}
|
|
311
|
+
.n-data-table-th--last {
|
|
312
|
+
border-right: 1px solid transparent;
|
|
313
|
+
}
|
|
314
|
+
.n-data-table-td--last-row {
|
|
315
|
+
border-bottom: 1px solid var(--n-merged-border-color);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.page-box {
|
|
321
|
+
display: flex;
|
|
322
|
+
flex-direction: column;
|
|
323
|
+
min-height: calc(100vh - 64px);
|
|
324
|
+
padding: 24px;
|
|
325
|
+
box-sizing: border-box;
|
|
326
|
+
background: #f5f5f5;
|
|
327
|
+
row-gap: 20px;
|
|
328
|
+
}
|
|
329
|
+
</style>
|
|
330
|
+
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="introduction-page">
|
|
3
|
+
<n-card class="intro-card">
|
|
4
|
+
<template #header>
|
|
5
|
+
<div class="header-content">
|
|
6
|
+
<h1 class="title">@xmszm/core</h1>
|
|
7
|
+
<n-tag type="info" size="small">v0.0.1</n-tag>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<div class="content">
|
|
12
|
+
<n-space vertical :size="24">
|
|
13
|
+
<!-- 项目简介 -->
|
|
14
|
+
<section>
|
|
15
|
+
<h2 class="section-title">
|
|
16
|
+
<n-icon :component="BookOutline" />
|
|
17
|
+
项目简介
|
|
18
|
+
</h2>
|
|
19
|
+
<p class="description">
|
|
20
|
+
<strong>@xmszm/core</strong> 是一个基于 Vue 3 + Naive UI 的组件与工具库,提供开箱即用的配置式表单、表格、弹窗等常用组件,以及丰富的工具函数集合。
|
|
21
|
+
</p>
|
|
22
|
+
</section>
|
|
23
|
+
|
|
24
|
+
<!-- 核心特性 -->
|
|
25
|
+
<section>
|
|
26
|
+
<h2 class="section-title">
|
|
27
|
+
<n-icon :component="SparklesOutline" />
|
|
28
|
+
核心特性
|
|
29
|
+
</h2>
|
|
30
|
+
<n-grid :cols="2" :x-gap="16" :y-gap="16">
|
|
31
|
+
<n-gi>
|
|
32
|
+
<n-card class="feature-card">
|
|
33
|
+
<n-space vertical :size="8">
|
|
34
|
+
<div class="feature-icon">
|
|
35
|
+
<n-icon :component="DocumentTextOutline" size="24" />
|
|
36
|
+
</div>
|
|
37
|
+
<h3 class="feature-title">配置化表单</h3>
|
|
38
|
+
<p class="feature-desc">
|
|
39
|
+
通过 Options 定义字段,自动生成 rules,轻松构建复杂表单
|
|
40
|
+
</p>
|
|
41
|
+
</n-space>
|
|
42
|
+
</n-card>
|
|
43
|
+
</n-gi>
|
|
44
|
+
<n-gi>
|
|
45
|
+
<n-card class="feature-card">
|
|
46
|
+
<n-space vertical :size="8">
|
|
47
|
+
<div class="feature-icon">
|
|
48
|
+
<n-icon :component="GridOutline" size="24" />
|
|
49
|
+
</div>
|
|
50
|
+
<h3 class="feature-title">表格增强</h3>
|
|
51
|
+
<p class="feature-desc">
|
|
52
|
+
内置操作列创建器、排序、筛选、虚拟滚动与省略 tooltip
|
|
53
|
+
</p>
|
|
54
|
+
</n-space>
|
|
55
|
+
</n-card>
|
|
56
|
+
</n-gi>
|
|
57
|
+
<n-gi>
|
|
58
|
+
<n-card class="feature-card">
|
|
59
|
+
<n-space vertical :size="8">
|
|
60
|
+
<div class="feature-icon">
|
|
61
|
+
<n-icon :component="SquareOutline" size="24" />
|
|
62
|
+
</div>
|
|
63
|
+
<h3 class="feature-title">弹窗集成</h3>
|
|
64
|
+
<p class="feature-desc">
|
|
65
|
+
commonDialogMethod 将表单与弹窗能力合并,减少样板代码
|
|
66
|
+
</p>
|
|
67
|
+
</n-space>
|
|
68
|
+
</n-card>
|
|
69
|
+
</n-gi>
|
|
70
|
+
<n-gi>
|
|
71
|
+
<n-card class="feature-card">
|
|
72
|
+
<n-space vertical :size="8">
|
|
73
|
+
<div class="feature-icon">
|
|
74
|
+
<n-icon :component="ConstructOutline" size="24" />
|
|
75
|
+
</div>
|
|
76
|
+
<h3 class="feature-title">实用工具</h3>
|
|
77
|
+
<p class="feature-desc">
|
|
78
|
+
上传、权限、路由 meta 初始化、数组对象转换等常用方法
|
|
79
|
+
</p>
|
|
80
|
+
</n-space>
|
|
81
|
+
</n-card>
|
|
82
|
+
</n-gi>
|
|
83
|
+
</n-grid>
|
|
84
|
+
</section>
|
|
85
|
+
|
|
86
|
+
<!-- 主要组件 -->
|
|
87
|
+
<section>
|
|
88
|
+
<h2 class="section-title">
|
|
89
|
+
<n-icon :component="CubeOutline" />
|
|
90
|
+
主要组件
|
|
91
|
+
</h2>
|
|
92
|
+
<n-list>
|
|
93
|
+
<n-list-item>
|
|
94
|
+
<n-thing title="DataForm" description="配置式表单组件,支持多种输入方式">
|
|
95
|
+
<template #avatar>
|
|
96
|
+
<n-icon :component="DocumentTextOutline" />
|
|
97
|
+
</template>
|
|
98
|
+
</n-thing>
|
|
99
|
+
</n-list-item>
|
|
100
|
+
<n-list-item>
|
|
101
|
+
<n-thing title="DataTable" description="增强型表格组件,支持排序、筛选、操作列">
|
|
102
|
+
<template #avatar>
|
|
103
|
+
<n-icon :component="GridOutline" />
|
|
104
|
+
</template>
|
|
105
|
+
</n-thing>
|
|
106
|
+
</n-list-item>
|
|
107
|
+
<n-list-item>
|
|
108
|
+
<n-thing title="CommonQuery" description="通用查询组件,快速构建查询表单">
|
|
109
|
+
<template #avatar>
|
|
110
|
+
<n-icon :component="SearchOutline" />
|
|
111
|
+
</template>
|
|
112
|
+
</n-thing>
|
|
113
|
+
</n-list-item>
|
|
114
|
+
<n-list-item>
|
|
115
|
+
<n-thing title="commonDialogMethod" description="弹窗方法,集成表单与弹窗功能">
|
|
116
|
+
<template #avatar>
|
|
117
|
+
<n-icon :component="SquareOutline" />
|
|
118
|
+
</template>
|
|
119
|
+
</n-thing>
|
|
120
|
+
</n-list-item>
|
|
121
|
+
<n-list-item>
|
|
122
|
+
<n-thing title="Options" description="选项配置组件,统一管理表单字段">
|
|
123
|
+
<template #avatar>
|
|
124
|
+
<n-icon :component="OptionsOutline" />
|
|
125
|
+
</template>
|
|
126
|
+
</n-thing>
|
|
127
|
+
</n-list-item>
|
|
128
|
+
</n-list>
|
|
129
|
+
</section>
|
|
130
|
+
|
|
131
|
+
<!-- 工具函数 -->
|
|
132
|
+
<section>
|
|
133
|
+
<h2 class="section-title">
|
|
134
|
+
<n-icon :component="HammerOutline" />
|
|
135
|
+
工具函数
|
|
136
|
+
</h2>
|
|
137
|
+
<n-space :size="8" wrap>
|
|
138
|
+
<n-tag>upload</n-tag>
|
|
139
|
+
<n-tag>auth</n-tag>
|
|
140
|
+
<n-tag>config</n-tag>
|
|
141
|
+
<n-tag>array</n-tag>
|
|
142
|
+
<n-tag>object</n-tag>
|
|
143
|
+
<n-tag>time</n-tag>
|
|
144
|
+
<n-tag>ellipsis</n-tag>
|
|
145
|
+
<n-tag>initRouteMeta</n-tag>
|
|
146
|
+
</n-space>
|
|
147
|
+
</section>
|
|
148
|
+
|
|
149
|
+
<!-- 技术栈 -->
|
|
150
|
+
<section>
|
|
151
|
+
<h2 class="section-title">
|
|
152
|
+
<n-icon :component="CodeWorkingOutline" />
|
|
153
|
+
技术栈
|
|
154
|
+
</h2>
|
|
155
|
+
<n-space :size="8" wrap>
|
|
156
|
+
<n-tag type="success">Vue 3</n-tag>
|
|
157
|
+
<n-tag type="success">Naive UI</n-tag>
|
|
158
|
+
<n-tag type="info">Vite</n-tag>
|
|
159
|
+
<n-tag type="info">VitePress</n-tag>
|
|
160
|
+
<n-tag type="warning">Day.js</n-tag>
|
|
161
|
+
<n-tag type="warning">Lodash</n-tag>
|
|
162
|
+
</n-space>
|
|
163
|
+
</section>
|
|
164
|
+
|
|
165
|
+
<!-- 快速开始 -->
|
|
166
|
+
<section>
|
|
167
|
+
<h2 class="section-title">
|
|
168
|
+
<n-icon :component="RocketOutline" />
|
|
169
|
+
快速开始
|
|
170
|
+
</h2>
|
|
171
|
+
<n-card class="code-card">
|
|
172
|
+
<n-code :code="installCode" language="bash" />
|
|
173
|
+
</n-card>
|
|
174
|
+
<n-card class="code-card">
|
|
175
|
+
<n-code :code="usageCode" language="javascript" />
|
|
176
|
+
</n-card>
|
|
177
|
+
</section>
|
|
178
|
+
</n-space>
|
|
179
|
+
</div>
|
|
180
|
+
</n-card>
|
|
181
|
+
</div>
|
|
182
|
+
</template>
|
|
183
|
+
|
|
184
|
+
<script setup>
|
|
185
|
+
import {
|
|
186
|
+
BookOutline,
|
|
187
|
+
CodeWorkingOutline,
|
|
188
|
+
ConstructOutline,
|
|
189
|
+
CubeOutline,
|
|
190
|
+
DocumentTextOutline,
|
|
191
|
+
GridOutline,
|
|
192
|
+
HammerOutline,
|
|
193
|
+
OptionsOutline,
|
|
194
|
+
RocketOutline,
|
|
195
|
+
SearchOutline,
|
|
196
|
+
SparklesOutline,
|
|
197
|
+
SquareOutline,
|
|
198
|
+
} from '@vicons/ionicons5'
|
|
199
|
+
import {
|
|
200
|
+
NCard,
|
|
201
|
+
NCode,
|
|
202
|
+
NGrid,
|
|
203
|
+
NGi,
|
|
204
|
+
NIcon,
|
|
205
|
+
NList,
|
|
206
|
+
NListItem,
|
|
207
|
+
NSpace,
|
|
208
|
+
NTag,
|
|
209
|
+
NThing,
|
|
210
|
+
} from 'naive-ui'
|
|
211
|
+
|
|
212
|
+
const installCode = `npm install @xmszm/core
|
|
213
|
+
|
|
214
|
+
# 或
|
|
215
|
+
pnpm add @xmszm/core
|
|
216
|
+
yarn add @xmszm/core`
|
|
217
|
+
|
|
218
|
+
const usageCode = `import { DataForm, DataTable, CommonQuery } from '@xmszm/core'
|
|
219
|
+
import '@xmszm/core/dist/style.css'
|
|
220
|
+
|
|
221
|
+
// 使用组件
|
|
222
|
+
<DataForm :options="formOptions" />
|
|
223
|
+
<DataTable :data="tableData" :columns="columns" />
|
|
224
|
+
<CommonQuery :query="query" :options="queryOptions" />`
|
|
225
|
+
</script>
|
|
226
|
+
|
|
227
|
+
<style scoped lang="less">
|
|
228
|
+
.introduction-page {
|
|
229
|
+
padding: 24px;
|
|
230
|
+
background: #f5f5f5;
|
|
231
|
+
min-height: 100vh;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.intro-card {
|
|
235
|
+
max-width: 1200px;
|
|
236
|
+
margin: 0 auto;
|
|
237
|
+
border-radius: 8px;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.header-content {
|
|
241
|
+
display: flex;
|
|
242
|
+
align-items: center;
|
|
243
|
+
gap: 12px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.title {
|
|
247
|
+
margin: 0;
|
|
248
|
+
font-size: 28px;
|
|
249
|
+
font-weight: 600;
|
|
250
|
+
color: #18a058;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.content {
|
|
254
|
+
padding: 8px 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.section-title {
|
|
258
|
+
display: flex;
|
|
259
|
+
align-items: center;
|
|
260
|
+
gap: 8px;
|
|
261
|
+
margin: 0 0 16px 0;
|
|
262
|
+
font-size: 20px;
|
|
263
|
+
font-weight: 600;
|
|
264
|
+
color: #333;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.description {
|
|
268
|
+
margin: 0;
|
|
269
|
+
line-height: 1.8;
|
|
270
|
+
color: #666;
|
|
271
|
+
font-size: 15px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.feature-card {
|
|
275
|
+
height: 100%;
|
|
276
|
+
transition: all 0.3s;
|
|
277
|
+
cursor: pointer;
|
|
278
|
+
|
|
279
|
+
&:hover {
|
|
280
|
+
transform: translateY(-4px);
|
|
281
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.feature-icon {
|
|
286
|
+
color: #18a058;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.feature-title {
|
|
290
|
+
margin: 0;
|
|
291
|
+
font-size: 16px;
|
|
292
|
+
font-weight: 600;
|
|
293
|
+
color: #333;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.feature-desc {
|
|
297
|
+
margin: 0;
|
|
298
|
+
font-size: 14px;
|
|
299
|
+
color: #666;
|
|
300
|
+
line-height: 1.6;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.code-card {
|
|
304
|
+
margin-top: 12px;
|
|
305
|
+
}
|
|
306
|
+
</style>
|
|
307
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
import { createRouter, createWebHistory } from 'vue-router'
|
|
3
|
+
import App from './App.vue'
|
|
4
|
+
import naive from 'naive-ui'
|
|
5
|
+
|
|
6
|
+
// 创建简单的路由配置(用于测试)
|
|
7
|
+
const router = createRouter({
|
|
8
|
+
history: createWebHistory(),
|
|
9
|
+
routes: [
|
|
10
|
+
{
|
|
11
|
+
path: '/',
|
|
12
|
+
component: App,
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const app = createApp(App)
|
|
18
|
+
app.use(naive)
|
|
19
|
+
app.use(router)
|
|
20
|
+
// 注意:permission 指令会在使用 Options 组件时自动注册,无需手动安装
|
|
21
|
+
app.mount('#app')
|
|
22
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 权限检查函数
|
|
3
|
+
* 使用方需要根据实际项目实现权限检查逻辑
|
|
4
|
+
*/
|
|
5
|
+
export function hasPermission(permission) {
|
|
6
|
+
// 测试用简单实现 - 实际项目中应该从 store 或 context 获取权限列表
|
|
7
|
+
console.log('检查权限:', permission)
|
|
8
|
+
|
|
9
|
+
// 示例:从 localStorage 或 store 获取权限
|
|
10
|
+
// const permissions = JSON.parse(localStorage.getItem('permissions') || '[]')
|
|
11
|
+
// return permissions.includes(permission)
|
|
12
|
+
|
|
13
|
+
// 测试环境:默认返回 true
|
|
14
|
+
return true
|
|
15
|
+
}
|
|
16
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 请求配置
|
|
3
|
+
* 使用方需要根据实际项目配置 API 基础地址
|
|
4
|
+
*/
|
|
5
|
+
export const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000'
|
|
6
|
+
|
|
7
|
+
// 如果需要,也可以导出其他请求相关的配置
|
|
8
|
+
// export const API_TIMEOUT = 10000
|
|
9
|
+
// export const API_HEADERS = { 'Content-Type': 'application/json' }
|
|
10
|
+
|