@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.
Files changed (77) hide show
  1. package/README.md +187 -0
  2. package/dist/index.cjs +2 -2
  3. package/dist/index.mjs +1431 -1170
  4. package/dist/plugin/vite/initRouteMeta.cjs +1 -0
  5. package/dist/plugin/vite/initRouteMeta.mjs +13 -0
  6. package/dist/style.css +1 -1
  7. package/docs/.vitepress/config.mjs +91 -0
  8. package/docs/components/config-options.md +125 -0
  9. package/docs/components/dataform.md +176 -23
  10. package/docs/components/datatable.md +58 -39
  11. package/docs/components/dialog.md +158 -19
  12. package/docs/components/options.md +44 -15
  13. package/docs/components/query.md +68 -14
  14. package/docs/components/utils.md +124 -16
  15. package/docs/guide/changelog.md +81 -0
  16. package/docs/guide/config.md +415 -0
  17. package/docs/guide/demo.md +2 -2
  18. package/docs/guide/local-development.md +109 -0
  19. package/docs/guide/quickstart.md +40 -11
  20. package/docs/index.md +3 -3
  21. package/docs/usage.md +30 -6
  22. package/examples/README.md +46 -0
  23. package/examples/index.html +14 -0
  24. package/examples/package.json +25 -0
  25. package/examples/pnpm-lock.yaml +1569 -0
  26. package/examples/pnpm-workspace.yaml +3 -0
  27. package/examples/src/AdminSystem.vue +870 -0
  28. package/examples/src/App.vue +330 -0
  29. package/examples/src/Introduction.vue +307 -0
  30. package/examples/src/main.js +22 -0
  31. package/examples/src/utils/permission.js +16 -0
  32. package/examples/src/utils/request.js +10 -0
  33. package/examples/vite.config.js +41 -0
  34. package/package.json +13 -4
  35. package/src/dialog/commonDialog.tsx +285 -0
  36. package/src/dialog/useCommonDialog.ts +41 -0
  37. package/src/dialog/utils/{dialog.js → dialog.ts} +2 -0
  38. package/src/directives/auto-register.ts +57 -0
  39. package/src/directives/permission.ts +67 -0
  40. package/src/enum/sort.tsx +45 -0
  41. package/src/form/DataForm.vue +34 -52
  42. package/src/index.ts +58 -0
  43. package/src/list/{useList.jsx → useList.tsx} +49 -14
  44. package/src/options/{Options.jsx → Options.tsx} +86 -72
  45. package/src/options/defaultOptions.tsx +656 -0
  46. package/src/plugin/index.ts +20 -0
  47. package/src/query/CommonQuery.vue +65 -90
  48. package/src/table/DataTable.vue +82 -95
  49. package/src/table/opr/{DataColumnCollet.jsx → DataColumnCollet.tsx} +18 -8
  50. package/src/table/opr/useDataColumn.tsx +226 -0
  51. package/src/table/opr/{useDataColumnButton.jsx → useDataColumnButton.tsx} +13 -6
  52. package/src/table/opr/{useDataColumnPop.jsx → useDataColumnPop.tsx} +13 -5
  53. package/src/table/opr/useQRCode.ts +40 -0
  54. package/src/utils/{array.js → array.ts} +4 -6
  55. package/src/utils/config.ts +192 -0
  56. package/src/utils/dialog.ts +110 -0
  57. package/src/utils/{object.js → object.ts} +1 -0
  58. package/src/utils/upload.ts +53 -0
  59. package/types/auto-imports.d.ts +78 -0
  60. package/types/components.d.ts +402 -0
  61. package/types/index.d.ts +145 -7
  62. package/types/plugin/vite/initRouteMeta.d.ts +23 -0
  63. package/types/src.d.ts +55 -0
  64. package/types/vue-shim.d.ts +9 -0
  65. package/examples/demo.vue +0 -224
  66. package/src/dialog/commonDialog.jsx +0 -230
  67. package/src/enum/sort.jsx +0 -31
  68. package/src/index.js +0 -46
  69. package/src/options/defaultOptions.jsx +0 -580
  70. package/src/table/opr/useDataColumn.jsx +0 -196
  71. package/src/utils/upload.js +0 -46
  72. /package/src/enum/{options.js → options.ts} +0 -0
  73. /package/src/plugin/vite/{initRouteMeta.js → initRouteMeta.ts} +0 -0
  74. /package/src/store/utils/{index.js → index.ts} +0 -0
  75. /package/src/table/utils/{ellipsis.js → ellipsis.ts} +0 -0
  76. /package/src/utils/{auth.js → auth.ts} +0 -0
  77. /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
+