@befly-addon/admin 1.0.9 → 1.0.11

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 (40) hide show
  1. package/apis/api/all.ts +5 -12
  2. package/apis/menu/all.ts +8 -14
  3. package/package.json +17 -3
  4. package/tables/admin.json +157 -13
  5. package/tables/api.json +79 -7
  6. package/tables/dict.json +79 -7
  7. package/tables/menu.json +79 -7
  8. package/tables/role.json +79 -7
  9. package/util.ts +1 -150
  10. package/views/403/index.vue +68 -0
  11. package/views/admin/components/edit.vue +150 -0
  12. package/views/admin/components/role.vue +138 -0
  13. package/views/admin/index.vue +179 -0
  14. package/views/dict/components/edit.vue +159 -0
  15. package/views/dict/index.vue +162 -0
  16. package/views/index/components/addonList.vue +127 -0
  17. package/views/index/components/environmentInfo.vue +99 -0
  18. package/views/index/components/operationLogs.vue +114 -0
  19. package/views/index/components/performanceMetrics.vue +150 -0
  20. package/views/index/components/quickActions.vue +27 -0
  21. package/views/index/components/serviceStatus.vue +183 -0
  22. package/views/index/components/systemNotifications.vue +132 -0
  23. package/views/index/components/systemOverview.vue +190 -0
  24. package/views/index/components/systemResources.vue +106 -0
  25. package/views/index/components/userInfo.vue +206 -0
  26. package/views/index/index.vue +29 -0
  27. package/views/login/components/emailLoginForm.vue +167 -0
  28. package/views/login/components/registerForm.vue +170 -0
  29. package/views/login/components/welcomePanel.vue +61 -0
  30. package/views/login/index.vue +191 -0
  31. package/views/menu/components/edit.vue +153 -0
  32. package/views/menu/index.vue +177 -0
  33. package/views/news/detail/index.vue +26 -0
  34. package/views/news/index.vue +26 -0
  35. package/views/role/components/api.vue +283 -0
  36. package/views/role/components/edit.vue +132 -0
  37. package/views/role/components/menu.vue +146 -0
  38. package/views/role/index.vue +179 -0
  39. package/views/user/index.vue +322 -0
  40. package/apis/dashboard/addonList.ts +0 -47
@@ -0,0 +1,132 @@
1
+ <template>
2
+ <tiny-dialog-box v-model:visible="$Data.visible" :title="$Prop.actionType === 'upd' ? '更新角色' : '添加角色'" width="600px" :append-to-body="true" :show-footer="true" :esc-closable="false" top="10vh" @close="$Method.onClose">
3
+ <div class="comp-role-edit">
4
+ <tiny-form :model="$Data.formData" label-width="120px" label-position="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
5
+ <tiny-form-item label="角色名称" prop="name">
6
+ <tiny-input v-model="$Data.formData.name" placeholder="请输入角色名称" />
7
+ </tiny-form-item>
8
+ <tiny-form-item label="角色代码" prop="code">
9
+ <tiny-input v-model="$Data.formData.code" placeholder="请输入角色代码,如:admin" />
10
+ </tiny-form-item>
11
+ <tiny-form-item label="角色描述" prop="description">
12
+ <tiny-input v-model="$Data.formData.description" type="textarea" placeholder="请输入角色描述" :rows="3" />
13
+ </tiny-form-item>
14
+ <tiny-form-item label="排序" prop="sort">
15
+ <tiny-numeric v-model="$Data.formData.sort" :min="0" :max="9999" />
16
+ </tiny-form-item>
17
+ <tiny-form-item label="状态" prop="state">
18
+ <tiny-radio-group v-model="$Data.formData.state">
19
+ <tiny-radio :label="1">正常</tiny-radio>
20
+ <tiny-radio :label="2">禁用</tiny-radio>
21
+ </tiny-radio-group>
22
+ </tiny-form-item>
23
+ </tiny-form>
24
+ </div>
25
+ <template #footer>
26
+ <tiny-button @click="$Method.onClose">取消</tiny-button>
27
+ <tiny-button type="primary" @click="$Method.onSubmit">确定</tiny-button>
28
+ </template>
29
+ </tiny-dialog-box>
30
+ </template>
31
+
32
+ <script setup>
33
+ import { ref, shallowRef } from 'vue';
34
+ import { Modal } from '@opentiny/vue';
35
+
36
+ const $Prop = defineProps({
37
+ modelValue: {
38
+ type: Boolean,
39
+ default: false
40
+ },
41
+ actionType: {
42
+ type: String,
43
+ default: 'add'
44
+ },
45
+ rowData: {
46
+ type: Object,
47
+ default: {}
48
+ }
49
+ });
50
+
51
+ const $Emit = defineEmits(['update:modelValue', 'success']);
52
+
53
+ // 表单引用
54
+ const $From = $shallowRef({
55
+ form: null
56
+ });
57
+
58
+ const $Computed = {};
59
+
60
+ const $Data = $ref({
61
+ visible: false,
62
+ formData: {
63
+ id: 0,
64
+ name: '',
65
+ code: '',
66
+ description: '',
67
+ sort: 0,
68
+ state: 1
69
+ }
70
+ });
71
+
72
+ const $Data2 = $shallowRef({
73
+ formRules: {
74
+ name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
75
+ code: [
76
+ { required: true, message: '请输入角色代码', trigger: 'blur' },
77
+ { pattern: /^[a-zA-Z0-9_]+$/, message: '角色代码只能包含字母、数字和下划线', trigger: 'blur' }
78
+ ],
79
+ sort: [{ type: 'number', message: '排序必须是数字', trigger: 'blur' }]
80
+ }
81
+ });
82
+
83
+ // 方法集合
84
+ const $Method = {
85
+ async initData() {
86
+ if ($Prop.actionType === 'upd' && $Prop.rowData.id) {
87
+ $Data.formData = Object.assign({}, $Prop.rowData);
88
+ }
89
+ $Method.onShow();
90
+ },
91
+ onShow() {
92
+ setTimeout(() => {
93
+ $Data.visible = $Prop.modelValue;
94
+ }, 100);
95
+ },
96
+ // 关闭抽屉事件
97
+ onClose() {
98
+ $Data.visible = false;
99
+ setTimeout(() => {
100
+ $Emit('update:modelValue', false);
101
+ }, 300);
102
+ },
103
+ async onSubmit() {
104
+ try {
105
+ const valid = await $From.form.validate();
106
+ if (!valid) return;
107
+
108
+ const res = await $Http($Prop.actionType === 'upd' ? '/addon/admin/roleUpd' : '/addon/admin/roleIns', $Data.formData);
109
+
110
+ Modal.message({
111
+ message: $Prop.actionType === 'upd' ? '更新成功' : '添加成功',
112
+ status: 'success'
113
+ });
114
+ $Data.visible = false;
115
+ $Emit('success');
116
+ } catch (error) {
117
+ console.error('提交失败:', error);
118
+ Modal.message({
119
+ message: '提交失败',
120
+ status: 'error'
121
+ });
122
+ }
123
+ }
124
+ };
125
+
126
+ $Method.initData();
127
+ </script>
128
+
129
+ <style scoped lang="scss">
130
+ .comp-role-edit {
131
+ }
132
+ </style>
@@ -0,0 +1,146 @@
1
+ <template>
2
+ <tiny-dialog-box v-model:visible="$Data.visible" title="菜单权限" width="600px" :append-to-body="true" :show-footer="true" top="10vh" @close="$Method.onClose">
3
+ <div class="comp-role-menu">
4
+ <tiny-tree :data="$Data.menuTreeData" node-key="id" show-checkbox default-expand-all :props="{ label: 'name' }" :ref="(el) => ($From.tree = el)" />
5
+ </div>
6
+ <template #footer>
7
+ <tiny-button @click="$Method.onClose">取消</tiny-button>
8
+ <tiny-button type="primary" @click="$Method.onSubmit">保存</tiny-button>
9
+ </template>
10
+ </tiny-dialog-box>
11
+ </template>
12
+
13
+ <script setup>
14
+ import { ref, nextTick, shallowRef } from 'vue';
15
+ import { Modal } from '@opentiny/vue';
16
+
17
+ import { arrayToTree } from '@/utils';
18
+
19
+ const $Prop = defineProps({
20
+ modelValue: {
21
+ type: Boolean,
22
+ default: false
23
+ },
24
+ rowData: {
25
+ type: Object,
26
+ default: () => ({})
27
+ }
28
+ });
29
+
30
+ const $Emit = defineEmits(['update:modelValue', 'success']);
31
+
32
+ // 表单引用
33
+ const $From = $shallowRef({
34
+ tree: null
35
+ });
36
+
37
+ const $Data = $ref({
38
+ visible: false,
39
+ menuTreeData: [],
40
+ menuTreeCheckedKeys: []
41
+ });
42
+
43
+ // 方法集合
44
+ const $Method = {
45
+ async initData() {
46
+ await Promise.all([$Method.apiMenuAll(), $Method.apiRoleMenuDetail()]);
47
+ $Method.onShow();
48
+ },
49
+
50
+ onShow() {
51
+ setTimeout(() => {
52
+ $Data.visible = $Prop.modelValue;
53
+ }, 100);
54
+ },
55
+
56
+ onClose() {
57
+ $Data.visible = false;
58
+ setTimeout(() => {
59
+ $Emit('update:modelValue', false);
60
+ }, 300);
61
+ },
62
+
63
+ // 加载菜单树(用于配置权限)
64
+ async apiMenuAll() {
65
+ try {
66
+ const res = await $Http('/addon/admin/menu/all');
67
+ // menuAll 返回的 data 直接就是菜单数组
68
+ const menuList = Array.isArray(res.data) ? res.data : [];
69
+ $Data.menuTreeData = arrayToTree(menuList);
70
+ } catch (error) {
71
+ console.error('加载菜单失败:', error);
72
+ Modal.message({ message: '加载菜单失败', status: 'error' });
73
+ }
74
+ },
75
+
76
+ // 加载该角色已分配的菜单
77
+ async apiRoleMenuDetail() {
78
+ if (!$Prop.rowData.id) return;
79
+
80
+ try {
81
+ const res = await $Http('/addon/admin/role/menuDetail', {
82
+ roleId: $Prop.rowData.id
83
+ });
84
+
85
+ // roleMenuDetail 返回的 data 直接就是菜单 ID 数组
86
+ $Data.menuTreeCheckedKeys = Array.isArray(res.data) ? res.data : [];
87
+
88
+ // 等待树渲染完成后设置选中状态
89
+ nextTick(() => {
90
+ if ($From.tree && $Data.menuTreeCheckedKeys.length > 0) {
91
+ $From.tree.setCheckedKeys($Data.menuTreeCheckedKeys);
92
+ }
93
+ });
94
+ } catch (error) {
95
+ console.error('加载角色菜单失败:', error);
96
+ }
97
+ },
98
+
99
+ // 提交表单
100
+ async onSubmit() {
101
+ try {
102
+ if (!$From.tree) {
103
+ Modal.message({ message: '菜单树未初始化', status: 'error' });
104
+ return;
105
+ }
106
+
107
+ // 获取选中的节点(包括半选中的父节点)
108
+ const checkedKeys = $From.tree.getCheckedKeys();
109
+ const halfCheckedKeys = $From.tree.getHalfCheckedKeys();
110
+ const menuIds = [...checkedKeys, ...halfCheckedKeys];
111
+
112
+ const res = await $Http('/addon/admin/role/menuSave', {
113
+ roleId: $Prop.rowData.id,
114
+ menuIds
115
+ });
116
+
117
+ if (res.code === 0) {
118
+ Modal.message({
119
+ message: '保存成功',
120
+ status: 'success'
121
+ });
122
+ $Data.visible = false;
123
+ $Emit('success');
124
+ } else {
125
+ Modal.message({
126
+ message: res.msg || '保存失败',
127
+ status: 'error'
128
+ });
129
+ }
130
+ } catch (error) {
131
+ console.error('保存失败:', error);
132
+ Modal.message({
133
+ message: '保存失败',
134
+ status: 'error'
135
+ });
136
+ }
137
+ }
138
+ };
139
+
140
+ $Method.initData();
141
+ </script>
142
+
143
+ <style scoped lang="scss">
144
+ .comp-role-menu {
145
+ }
146
+ </style>
@@ -0,0 +1,179 @@
1
+ <template>
2
+ <div class="page-role page-table">
3
+ <div class="main-tool">
4
+ <div class="left">
5
+ <tiny-button type="primary" @click="$Method.onAction('add', {})">
6
+ <template #icon>
7
+ <i-lucide:plus style="width: 16px; height: 16px" />
8
+ </template>
9
+ 添加角色
10
+ </tiny-button>
11
+ </div>
12
+ <div class="right">
13
+ <tiny-button @click="$Method.handleRefresh">
14
+ <template #icon>
15
+ <i-lucide:rotate-cw style="width: 16px; height: 16px" />
16
+ </template>
17
+ 刷新
18
+ </tiny-button>
19
+ </div>
20
+ </div>
21
+ <div class="main-table">
22
+ <tiny-grid :data="$Data.tableData" header-cell-class-name="custom-table-cell-class" size="small" height="100%" show-overflow="tooltip" border seq-serial>
23
+ <tiny-grid-column type="index" title="序号" align="center" :width="100" />
24
+ <tiny-grid-column field="name" title="角色名称" :width="150" />
25
+ <tiny-grid-column field="code" title="角色代码" :width="150" />
26
+ <tiny-grid-column field="description" title="描述" :min-width="150" />
27
+ <tiny-grid-column field="sort" title="排序" align="center" :width="80" />
28
+ <tiny-grid-column field="state" title="状态" align="center" :width="100">
29
+ <template #default="{ row }">
30
+ <tiny-tag v-if="row.state === 1" type="success">正常</tiny-tag>
31
+ <tiny-tag v-else-if="row.state === 2" type="warning">禁用</tiny-tag>
32
+ <tiny-tag v-else type="danger">已删除</tiny-tag>
33
+ </template>
34
+ </tiny-grid-column>
35
+ <tiny-grid-column title="操作" :width="120" align="center" fixed="right">
36
+ <template #default="{ row }">
37
+ <tiny-dropdown title="操作" trigger="click" size="small" border visible-arrow @item-click="(data) => $Method.onAction(data.itemData.command, row)">
38
+ <template #dropdown>
39
+ <tiny-dropdown-menu>
40
+ <tiny-dropdown-item :item-data="{ command: 'upd' }">
41
+ <i-lucide:pencil style="width: 14px; height: 14px; margin-right: 6px" />
42
+ 编辑
43
+ </tiny-dropdown-item>
44
+ <tiny-dropdown-item :item-data="{ command: 'menu' }">
45
+ <i-lucide:settings style="width: 14px; height: 14px; margin-right: 6px" />
46
+ 菜单权限
47
+ </tiny-dropdown-item>
48
+ <tiny-dropdown-item :item-data="{ command: 'api' }">
49
+ <i-lucide:code style="width: 14px; height: 14px; margin-right: 6px" />
50
+ 接口权限
51
+ </tiny-dropdown-item>
52
+ <tiny-dropdown-item :item-data="{ command: 'del' }" divided>
53
+ <i-lucide:trash-2 style="width: 14px; height: 14px; margin-right: 6px" />
54
+ 删除
55
+ </tiny-dropdown-item>
56
+ </tiny-dropdown-menu>
57
+ </template>
58
+ </tiny-dropdown>
59
+ </template>
60
+ </tiny-grid-column>
61
+ </tiny-grid>
62
+ </div>
63
+
64
+ <div class="main-page">
65
+ <tiny-pager :current-page="$Data.pagerConfig.currentPage" :page-size="$Data.pagerConfig.pageSize" :total="$Data.pagerConfig.total" @current-change="$Method.onPageChange" @size-change="$Method.handleSizeChange" />
66
+ </div>
67
+
68
+ <!-- 编辑对话框组件 -->
69
+ <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="$Method.apiRoleList" />
70
+
71
+ <!-- 菜单权限对话框组件 -->
72
+ <MenuDialog v-if="$Data.menuVisible" v-model="$Data.menuVisible" :row-data="$Data.rowData" @success="$Method.apiRoleList" />
73
+
74
+ <!-- 接口权限对话框组件 -->
75
+ <ApiDialog v-if="$Data.apiVisible" v-model="$Data.apiVisible" :row-data="$Data.rowData" @success="$Method.apiRoleList" />
76
+ </div>
77
+ </template>
78
+
79
+ <script setup>
80
+ import EditDialog from './components/edit.vue';
81
+ import MenuDialog from './components/menu.vue';
82
+ import ApiDialog from './components/api.vue';
83
+
84
+ // 响应式数据
85
+ const $Data = $ref({
86
+ tableData: [],
87
+ pagerConfig: {
88
+ currentPage: 1,
89
+ pageSize: 30,
90
+ total: 0,
91
+ align: 'right',
92
+ layout: 'total, prev, pager, next, jumper'
93
+ },
94
+ editVisible: false,
95
+ menuVisible: false,
96
+ apiVisible: false,
97
+ actionType: 'add',
98
+ rowData: {}
99
+ });
100
+
101
+ // 方法
102
+ const $Method = {
103
+ async initData() {
104
+ await $Method.apiRoleList();
105
+ },
106
+ // 加载角色列表
107
+ async apiRoleList() {
108
+ try {
109
+ const res = await $Http('/addon/admin/role/list', {
110
+ page: $Data.pagerConfig.currentPage,
111
+ limit: $Data.pagerConfig.limit
112
+ });
113
+ $Data.tableData = res.data.lists || [];
114
+ $Data.pagerConfig.total = res.data.total || 0;
115
+ } catch (error) {
116
+ console.error('加载角色列表失败:', error);
117
+ Modal.message({
118
+ message: '加载数据失败',
119
+ status: 'error'
120
+ });
121
+ }
122
+ },
123
+
124
+ // 删除角色
125
+ async apiRoleDel(row) {
126
+ Modal.confirm({
127
+ header: '确认删除',
128
+ body: `确定要删除角色"${row.name}" 吗?`,
129
+ status: 'warning'
130
+ }).then(async () => {
131
+ try {
132
+ const res = await $Http('/addon/admin/role/del', { id: row.id });
133
+ if (res.code === 0) {
134
+ Modal.message({ message: '删除成功', status: 'success' });
135
+ $Method.apiRoleList();
136
+ } else {
137
+ Modal.message({ message: res.msg || '删除失败', status: 'error' });
138
+ }
139
+ } catch (error) {
140
+ console.error('删除失败:', error);
141
+ Modal.message({ message: '删除失败', status: 'error' });
142
+ }
143
+ });
144
+ },
145
+
146
+ // 刷新
147
+ handleRefresh() {
148
+ $Method.apiRoleList();
149
+ },
150
+
151
+ // 分页改变
152
+ onPageChange({ currentPage }) {
153
+ $Data.pagerConfig.currentPage = currentPage;
154
+ $Method.apiRoleList();
155
+ },
156
+
157
+ // 操作菜单点击
158
+ onAction(command, rowData) {
159
+ $Data.actionType = command;
160
+ $Data.rowData = rowData;
161
+ if (command === 'add' || command === 'upd') {
162
+ $Data.editVisible = true;
163
+ } else if (command === 'menu') {
164
+ $Data.menuVisible = true;
165
+ } else if (command === 'api') {
166
+ $Data.apiVisible = true;
167
+ } else if (command === 'del') {
168
+ $Method.apiRoleDel(rowData);
169
+ }
170
+ }
171
+ };
172
+
173
+ $Method.initData();
174
+ </script>
175
+
176
+ <style scoped lang="scss">
177
+ .page-role {
178
+ }
179
+ </style>