@befly-addon/admin 1.2.0 → 1.2.2

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 (36) hide show
  1. package/adminViews/403_1/index.vue +75 -0
  2. package/adminViews/config/dict/components/edit.vue +109 -0
  3. package/adminViews/config/dict/index.vue +266 -0
  4. package/adminViews/config/dictType/components/edit.vue +100 -0
  5. package/adminViews/config/dictType/index.vue +244 -0
  6. package/adminViews/config/index.vue +12 -0
  7. package/adminViews/config/system/components/edit.vue +171 -0
  8. package/adminViews/config/system/index.vue +286 -0
  9. package/adminViews/index/components/addonList.vue +132 -0
  10. package/adminViews/index/components/environmentInfo.vue +100 -0
  11. package/adminViews/index/components/operationLogs.vue +112 -0
  12. package/adminViews/index/components/performanceMetrics.vue +145 -0
  13. package/adminViews/index/components/quickActions.vue +30 -0
  14. package/adminViews/index/components/serviceStatus.vue +192 -0
  15. package/adminViews/index/components/systemNotifications.vue +137 -0
  16. package/adminViews/index/components/systemOverview.vue +190 -0
  17. package/adminViews/index/components/systemResources.vue +111 -0
  18. package/adminViews/index/components/userInfo.vue +204 -0
  19. package/adminViews/index/index.vue +74 -0
  20. package/adminViews/log/email/index.vue +292 -0
  21. package/adminViews/log/index.vue +12 -0
  22. package/adminViews/log/login/index.vue +187 -0
  23. package/adminViews/log/operate/index.vue +249 -0
  24. package/adminViews/login_1/index.vue +415 -0
  25. package/adminViews/people/admin/components/edit.vue +168 -0
  26. package/adminViews/people/admin/index.vue +240 -0
  27. package/adminViews/people/index.vue +12 -0
  28. package/adminViews/permission/api/index.vue +149 -0
  29. package/adminViews/permission/index.vue +12 -0
  30. package/adminViews/permission/menu/index.vue +130 -0
  31. package/adminViews/permission/role/components/api.vue +361 -0
  32. package/adminViews/permission/role/components/edit.vue +142 -0
  33. package/adminViews/permission/role/components/menu.vue +118 -0
  34. package/adminViews/permission/role/index.vue +263 -0
  35. package/package.json +12 -10
  36. package/tsconfig.json +15 -0
@@ -0,0 +1,240 @@
1
+ <template>
2
+ <div class="page-admin page-table">
3
+ <div class="main-tool">
4
+ <div class="left">
5
+ <TButton theme="primary" @click="$Method.onAction('add', {})">
6
+ <template #icon>
7
+ <ILucidePlus />
8
+ </template>
9
+ </TButton>
10
+ </div>
11
+ <div class="right">
12
+ <TButton shape="circle" @click="$Method.handleRefresh">
13
+ <template #icon>
14
+ <ILucideRotateCw />
15
+ </template>
16
+ </TButton>
17
+ </div>
18
+ </div>
19
+
20
+ <div class="main-content">
21
+ <div class="main-table">
22
+ <TTable
23
+ :data="$Data.tableData"
24
+ :columns="$Data.columns"
25
+ :loading="$Data.loading"
26
+ :active-row-keys="$Data.activeRowKeys"
27
+ row-key="id"
28
+ height="calc(100vh - var(--search-height) - var(--pagination-height) - var(--layout-gap) * 4)"
29
+ active-row-type="single"
30
+ @active-change="$Method.onActiveChange"
31
+ >
32
+ <template #state="{ row }">
33
+ <TTag v-if="row.state === 1" shape="round" theme="success" variant="light-outline">正常</TTag>
34
+ <TTag v-else-if="row.state === 2" shape="round" theme="warning" variant="light-outline">禁用</TTag>
35
+ <TTag v-else-if="row.state === 0" shape="round" theme="danger" variant="light-outline">删除</TTag>
36
+ </template>
37
+ <template #operation="{ row }">
38
+ <TDropdown trigger="click" placement="bottom-right" @click="(data) => $Method.onAction(data.value, row)">
39
+ <TButton theme="primary" size="small">
40
+ 操作
41
+ <template #suffix> <ILucideChevronDown /></template>
42
+ </TButton>
43
+ <TDropdownMenu slot="dropdown">
44
+ <TDropdownItem value="upd">
45
+ <ILucidePencil />
46
+ 编辑
47
+ </TDropdownItem>
48
+ <TDropdownItem value="del" :divider="true">
49
+ <ILucideTrash2 />
50
+ 删除
51
+ </TDropdownItem>
52
+ </TDropdownMenu>
53
+ </TDropdown>
54
+ </template>
55
+ </TTable>
56
+ </div>
57
+
58
+ <div class="main-detail">
59
+ <DetailPanel :data="$Data.currentRow" :fields="$Data.columns" />
60
+ </div>
61
+ </div>
62
+
63
+ <div class="main-page">
64
+ <TPagination :current-page="$Data.pagerConfig.currentPage" :page-size="$Data.pagerConfig.limit" :total="$Data.pagerConfig.total" @current-change="$Method.onPageChange" @page-size-change="$Method.handleSizeChange" />
65
+ </div>
66
+
67
+ <!-- 编辑对话框组件 -->
68
+ <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="$Method.apiAdminList" />
69
+ </div>
70
+ </template>
71
+
72
+ <script setup>
73
+ import { Button as TButton, Table as TTable, Tag as TTag, Dropdown as TDropdown, DropdownMenu as TDropdownMenu, DropdownItem as TDropdownItem, Pagination as TPagination, MessagePlugin, DialogPlugin } from "tdesign-vue-next";
74
+ import ILucidePlus from "~icons/lucide/plus";
75
+ import ILucideRotateCw from "~icons/lucide/rotate-cw";
76
+ import ILucidePencil from "~icons/lucide/pencil";
77
+ import ILucideTrash2 from "~icons/lucide/trash-2";
78
+ import ILucideChevronDown from "~icons/lucide/chevron-down";
79
+ import EditDialog from "./components/edit.vue";
80
+ import DetailPanel from "@/components/DetailPanel.vue";
81
+ import { $Http } from "@/plugins/http";
82
+ import { withDefaultColumns } from "befly-vite/utils/withDefaultColumns";
83
+
84
+ definePage({
85
+ meta: {
86
+ title: "管理员",
87
+ order: 1
88
+ }
89
+ });
90
+
91
+ // 响应式数据
92
+ const $Data = $ref({
93
+ tableData: [],
94
+ loading: false,
95
+ columns: withDefaultColumns([
96
+ { colKey: "username", title: "用户名", fixed: "left" },
97
+ { colKey: "id", title: "序号" },
98
+ { colKey: "nickname", title: "昵称" },
99
+ { colKey: "roleCode", title: "角色" },
100
+ { colKey: "state", title: "状态" },
101
+ { colKey: "operation", title: "操作" }
102
+ ]),
103
+ pagerConfig: {
104
+ currentPage: 1,
105
+ limit: 30,
106
+ total: 0,
107
+ align: "right",
108
+ layout: "total, prev, pager, next, jumper"
109
+ },
110
+ editVisible: false,
111
+ actionType: "add",
112
+ rowData: {},
113
+ currentRow: null,
114
+ activeRowKeys: []
115
+ });
116
+
117
+ // 方法
118
+ const $Method = {
119
+ async initData() {
120
+ await $Method.apiAdminList();
121
+ },
122
+
123
+ // 加载管理员列表
124
+ async apiAdminList() {
125
+ $Data.loading = true;
126
+ try {
127
+ const res = await $Http("/addon/admin/admin/list", {
128
+ page: $Data.pagerConfig.currentPage,
129
+ limit: $Data.pagerConfig.limit
130
+ });
131
+ $Data.tableData = res.data.lists || [];
132
+ $Data.pagerConfig.total = res.data.total || 0;
133
+
134
+ // 自动高亮第一行
135
+ if ($Data.tableData.length > 0) {
136
+ $Data.currentRow = $Data.tableData[0];
137
+ $Data.activeRowKeys = [$Data.tableData[0].id];
138
+ } else {
139
+ $Data.currentRow = null;
140
+ $Data.activeRowKeys = [];
141
+ }
142
+ } catch (error) {
143
+ MessagePlugin.error("加载数据失败");
144
+ } finally {
145
+ $Data.loading = false;
146
+ }
147
+ },
148
+
149
+ // 删除管理员
150
+ async apiAdminDel(row) {
151
+ let dialog = null;
152
+ let destroyed = false;
153
+
154
+ const destroy = () => {
155
+ if (destroyed) return;
156
+ destroyed = true;
157
+ if (dialog && typeof dialog.destroy === "function") {
158
+ dialog.destroy();
159
+ }
160
+ };
161
+
162
+ dialog = DialogPlugin.confirm({
163
+ header: "确认删除",
164
+ body: `确认删除管理员“${row.username}”吗?`,
165
+ status: "warning",
166
+ confirmBtn: "删除",
167
+ cancelBtn: "取消",
168
+ onConfirm: async () => {
169
+ if (dialog && typeof dialog.setConfirmLoading === "function") {
170
+ dialog.setConfirmLoading(true);
171
+ }
172
+
173
+ try {
174
+ await $Http("/addon/admin/admin/del", { id: row.id });
175
+ MessagePlugin.success("删除成功");
176
+ destroy();
177
+ await $Method.apiAdminList();
178
+ } catch (error) {
179
+ MessagePlugin.error("删除失败");
180
+ } finally {
181
+ if (dialog && typeof dialog.setConfirmLoading === "function") {
182
+ dialog.setConfirmLoading(false);
183
+ }
184
+ }
185
+ },
186
+ onClose: () => {
187
+ destroy();
188
+ }
189
+ });
190
+ },
191
+
192
+ // 刷新
193
+ handleRefresh() {
194
+ $Method.apiAdminList();
195
+ },
196
+
197
+ // 分页改变
198
+ onPageChange({ currentPage }) {
199
+ $Data.pagerConfig.currentPage = currentPage;
200
+ $Method.apiAdminList();
201
+ },
202
+
203
+ // 每页条数改变
204
+ handleSizeChange({ pageSize }) {
205
+ $Data.pagerConfig.limit = pageSize;
206
+ $Data.pagerConfig.currentPage = 1;
207
+ $Method.apiAdminList();
208
+ },
209
+
210
+ // 高亮行变化
211
+ onActiveChange(value, context) {
212
+ // 禁止取消高亮:如果新值为空,保持当前选中
213
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
214
+ return;
215
+ }
216
+ $Data.activeRowKeys = value;
217
+ // 更新当前高亮的行数据
218
+ if (context.activeRowList && context.activeRowList.length > 0) {
219
+ $Data.currentRow = context.activeRowList[0].row;
220
+ }
221
+ },
222
+
223
+ // 操作菜单点击
224
+ onAction(command, rowData) {
225
+ $Data.actionType = command;
226
+ $Data.rowData = rowData;
227
+ if (command === "add" || command === "upd") {
228
+ $Data.editVisible = true;
229
+ } else if (command === "del") {
230
+ $Method.apiAdminDel(rowData);
231
+ }
232
+ }
233
+ };
234
+
235
+ $Method.initData();
236
+ </script>
237
+
238
+ <style scoped lang="scss">
239
+ // 样式继承自全局 page-table
240
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <RouterView />
3
+ </template>
4
+
5
+ <script setup>
6
+ definePage({
7
+ meta: {
8
+ title: "人员管理",
9
+ order: 10
10
+ }
11
+ });
12
+ </script>
@@ -0,0 +1,149 @@
1
+ <template>
2
+ <div class="page-api page-table">
3
+ <div class="main-tool">
4
+ <div class="left">
5
+ <TInput v-model="$Data.searchKeyword" placeholder="搜索接口名称或路径" clearable style="width: 300px" @enter="$Method.handleSearch" @clear="$Method.handleSearch">
6
+ <template #suffix-icon>
7
+ <ILucideSearch />
8
+ </template>
9
+ </TInput>
10
+ <span style="margin-left: 16px; color: var(--text-secondary); font-size: 13px">共 {{ $Data.allData.length }} 个接口</span>
11
+ </div>
12
+ <div class="right">
13
+ <TButton shape="circle" @click="$Method.handleRefresh">
14
+ <template #icon>
15
+ <ILucideRotateCw />
16
+ </template>
17
+ </TButton>
18
+ </div>
19
+ </div>
20
+
21
+ <div class="main-content">
22
+ <div class="main-table">
23
+ <TTable :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="calc(100vh - var(--search-height) - var(--layout-gap) * 2)" active-row-type="single" @active-change="$Method.onActiveChange">
24
+ <template #method="{ row }">
25
+ <TTag v-if="row.method === 'GET'" shape="round" theme="success" variant="light-outline">GET</TTag>
26
+ <TTag v-else-if="row.method === 'POST'" shape="round" theme="primary" variant="light-outline">POST</TTag>
27
+ <TTag v-else-if="row.method === 'PUT'" shape="round" theme="warning" variant="light-outline">PUT</TTag>
28
+ <TTag v-else-if="row.method === 'DELETE'" shape="round" theme="danger" variant="light-outline">DELETE</TTag>
29
+ <TTag v-else shape="round" variant="light-outline">{{ row.method }}</TTag>
30
+ </template>
31
+ <template #addonName="{ row }">
32
+ <TTag v-if="row.addonName" shape="round" variant="light-outline">{{ row.addonTitle || row.addonName }}</TTag>
33
+ <span v-else>项目</span>
34
+ </template>
35
+ </TTable>
36
+ </div>
37
+
38
+ <div class="main-detail">
39
+ <DetailPanel :data="$Data.currentRow" :fields="$Data.columns">
40
+ <template #method="{ value }">
41
+ <TTag v-if="value === 'GET'" shape="round" theme="success" variant="light-outline">GET</TTag>
42
+ <TTag v-else-if="value === 'POST'" shape="round" theme="primary" variant="light-outline">POST</TTag>
43
+ <TTag v-else-if="value === 'PUT'" shape="round" theme="warning" variant="light-outline">PUT</TTag>
44
+ <TTag v-else-if="value === 'DELETE'" shape="round" theme="danger" variant="light-outline">DELETE</TTag>
45
+ <TTag v-else shape="round" variant="light-outline">{{ value }}</TTag>
46
+ </template>
47
+ </DetailPanel>
48
+ </div>
49
+ </div>
50
+ </div>
51
+ </template>
52
+
53
+ <script setup>
54
+ import { Button as TButton, Table as TTable, Tag as TTag, Input as TInput, MessagePlugin } from "tdesign-vue-next";
55
+ import ILucideRotateCw from "~icons/lucide/rotate-cw";
56
+ import ILucideSearch from "~icons/lucide/search";
57
+ import { $Http } from "@/plugins/http";
58
+ import { withDefaultColumns } from "befly-vite/utils/withDefaultColumns";
59
+ import DetailPanel from "@/components/DetailPanel.vue";
60
+
61
+ definePage({
62
+ meta: {
63
+ title: "接口列表",
64
+ order: 3
65
+ }
66
+ });
67
+
68
+ // 响应式数据
69
+ const $Data = $ref({
70
+ tableData: [],
71
+ allData: [],
72
+ loading: false,
73
+ searchKeyword: "",
74
+ columns: withDefaultColumns([
75
+ { colKey: "name", title: "接口名称" },
76
+ { colKey: "id", title: "序号" },
77
+ { colKey: "path", title: "接口路径" },
78
+ { colKey: "method", title: "请求方法" },
79
+ { colKey: "addonName", title: "所属组件" }
80
+ ]),
81
+ currentRow: null,
82
+ activeRowKeys: []
83
+ });
84
+
85
+ // 方法
86
+ const $Method = {
87
+ async initData() {
88
+ await $Method.loadApiAll();
89
+ },
90
+
91
+ // 加载全部接口
92
+ async loadApiAll() {
93
+ $Data.loading = true;
94
+ try {
95
+ const res = await $Http("/addon/admin/api/all");
96
+ const list = res.data?.lists || [];
97
+ $Data.allData = list;
98
+ $Data.tableData = list;
99
+
100
+ // 自动高亮第一行
101
+ if ($Data.tableData.length > 0) {
102
+ $Data.currentRow = $Data.tableData[0];
103
+ $Data.activeRowKeys = [$Data.tableData[0].id];
104
+ } else {
105
+ $Data.currentRow = null;
106
+ $Data.activeRowKeys = [];
107
+ }
108
+ } catch (error) {
109
+ MessagePlugin.error("加载数据失败");
110
+ } finally {
111
+ $Data.loading = false;
112
+ }
113
+ },
114
+
115
+ // 刷新
116
+ handleRefresh() {
117
+ $Method.loadApiAll();
118
+ },
119
+
120
+ // 搜索
121
+ handleSearch() {
122
+ if (!$Data.searchKeyword) {
123
+ $Data.tableData = $Data.allData;
124
+ return;
125
+ }
126
+ const keyword = $Data.searchKeyword.toLowerCase();
127
+ $Data.tableData = $Data.allData.filter((item) => item.name?.toLowerCase().includes(keyword) || item.path?.toLowerCase().includes(keyword));
128
+ },
129
+
130
+ // 高亮行变化
131
+ onActiveChange(value, context) {
132
+ // 禁止取消高亮:如果新值为空,保持当前选中
133
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
134
+ return;
135
+ }
136
+ $Data.activeRowKeys = value;
137
+ // 更新当前高亮的行数据
138
+ if (context.activeRowList && context.activeRowList.length > 0) {
139
+ $Data.currentRow = context.activeRowList[0].row;
140
+ }
141
+ }
142
+ };
143
+
144
+ $Method.initData();
145
+ </script>
146
+
147
+ <style scoped lang="scss">
148
+ // 样式继承自全局 page-table
149
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <RouterView />
3
+ </template>
4
+
5
+ <script setup>
6
+ definePage({
7
+ meta: {
8
+ title: "权限设置",
9
+ order: 20
10
+ }
11
+ });
12
+ </script>
@@ -0,0 +1,130 @@
1
+ <template>
2
+ <div class="page-menu page-table">
3
+ <div class="main-tool">
4
+ <div class="left"></div>
5
+ <div class="right">
6
+ <TButton shape="circle" @click="$Method.handleRefresh">
7
+ <template #icon>
8
+ <ILucideRotateCw />
9
+ </template>
10
+ </TButton>
11
+ </div>
12
+ </div>
13
+
14
+ <div class="main-content">
15
+ <div class="main-table">
16
+ <TTable
17
+ :data="$Data.tableData"
18
+ :columns="$Data.columns"
19
+ :loading="$Data.loading"
20
+ :active-row-keys="$Data.activeRowKeys"
21
+ row-key="id"
22
+ height="calc(100vh - var(--search-height) - var(--layout-gap) * 2)"
23
+ active-row-type="single"
24
+ :tree="{ childrenKey: 'children', treeNodeColumnIndex: 0, defaultExpandAll: true }"
25
+ @active-change="$Method.onActiveChange"
26
+ >
27
+ <template #state="{ row }">
28
+ <TTag v-if="row.state === 1" shape="round" theme="success" variant="light-outline">正常</TTag>
29
+ <TTag v-else-if="row.state === 2" shape="round" theme="warning" variant="light-outline">禁用</TTag>
30
+ <TTag v-else-if="row.state === 0" shape="round" theme="danger" variant="light-outline">删除</TTag>
31
+ </template>
32
+ </TTable>
33
+ </div>
34
+
35
+ <div class="main-detail">
36
+ <DetailPanel :data="$Data.currentRow" :fields="$Data.columns" />
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </template>
41
+
42
+ <script setup>
43
+ import { Button as TButton, Table as TTable, Tag as TTag, MessagePlugin } from "tdesign-vue-next";
44
+ import ILucideRotateCw from "~icons/lucide/rotate-cw";
45
+ import DetailPanel from "@/components/DetailPanel.vue";
46
+ import { $Http } from "@/plugins/http";
47
+ import { arrayToTree } from "befly-shared/utils/arrayToTree";
48
+ import { withDefaultColumns } from "befly-vite/utils/withDefaultColumns";
49
+
50
+ definePage({
51
+ meta: {
52
+ title: "菜单列表",
53
+ order: 2
54
+ }
55
+ });
56
+
57
+ // 响应式数据
58
+ const $Data = $ref({
59
+ tableData: [],
60
+ loading: false,
61
+ columns: withDefaultColumns([
62
+ { colKey: "name", title: "菜单名称" },
63
+ { colKey: "id", title: "序号" },
64
+ { colKey: "path", title: "路由路径" },
65
+ { colKey: "parentPath", title: "父级路径" },
66
+ { colKey: "sort", title: "排序" },
67
+ { colKey: "state", title: "状态" }
68
+ ]),
69
+ currentRow: null,
70
+ activeRowKeys: []
71
+ });
72
+
73
+ // 方法
74
+ const $Method = {
75
+ async initData() {
76
+ await $Method.apiMenuList();
77
+ },
78
+
79
+ // 加载菜单列表(树形结构)
80
+ async apiMenuList() {
81
+ $Data.loading = true;
82
+ try {
83
+ const res = await $Http("/addon/admin/menu/all");
84
+ const lists = Array.isArray(res?.data?.lists) ? res.data.lists : [];
85
+
86
+ const treeResult = arrayToTree(lists, "path", "parentPath", "children", "sort");
87
+
88
+ // 构建树形结构(TTable tree)
89
+ $Data.tableData = treeResult.tree;
90
+
91
+ // 自动高亮第一行
92
+ if ($Data.tableData.length > 0) {
93
+ $Data.currentRow = $Data.tableData[0];
94
+ $Data.activeRowKeys = [$Data.tableData[0].id];
95
+ } else {
96
+ $Data.currentRow = null;
97
+ $Data.activeRowKeys = [];
98
+ }
99
+ } catch (error) {
100
+ MessagePlugin.error("加载数据失败");
101
+ } finally {
102
+ $Data.loading = false;
103
+ }
104
+ },
105
+
106
+ // 刷新
107
+ handleRefresh() {
108
+ $Method.apiMenuList();
109
+ },
110
+
111
+ // 高亮行变化
112
+ onActiveChange(value, context) {
113
+ // 禁止取消高亮:如果新值为空,保持当前选中
114
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
115
+ return;
116
+ }
117
+ $Data.activeRowKeys = value;
118
+ // 更新当前高亮的行数据
119
+ if (context.activeRowList && context.activeRowList.length > 0) {
120
+ $Data.currentRow = context.activeRowList[0].row;
121
+ }
122
+ }
123
+ };
124
+
125
+ $Method.initData();
126
+ </script>
127
+
128
+ <style scoped lang="scss">
129
+ // 样式继承自全局 page-table
130
+ </style>