@befly-addon/admin 1.0.55 → 1.0.56

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 (61) hide show
  1. package/apis/admin/ins.ts +11 -15
  2. package/apis/admin/upd.ts +1 -13
  3. package/apis/auth/login.ts +49 -5
  4. package/apis/email/config.ts +16 -0
  5. package/apis/email/logList.ts +13 -0
  6. package/apis/email/send.ts +42 -0
  7. package/apis/email/verify.ts +12 -0
  8. package/apis/loginLog/list.ts +13 -0
  9. package/apis/operateLog/list.ts +13 -0
  10. package/apis/sysConfig/all.ts +12 -0
  11. package/apis/sysConfig/del.ts +30 -0
  12. package/apis/sysConfig/get.ts +31 -0
  13. package/apis/sysConfig/ins.ts +38 -0
  14. package/apis/sysConfig/list.ts +14 -0
  15. package/apis/sysConfig/upd.ts +50 -0
  16. package/package.json +14 -3
  17. package/plugins/email.ts +206 -0
  18. package/styles/variables.scss +121 -60
  19. package/tables/admin.json +0 -15
  20. package/tables/emailLog.json +69 -0
  21. package/tables/loginLog.json +96 -0
  22. package/tables/operateLog.json +82 -0
  23. package/tables/role.json +1 -1
  24. package/tables/sysConfig.json +53 -0
  25. package/views/403_1/meta.json +4 -0
  26. package/views/{dict → config/dict}/index.vue +27 -38
  27. package/views/config/dict/meta.json +4 -0
  28. package/views/config/meta.json +4 -0
  29. package/views/config/system/components/edit.vue +179 -0
  30. package/views/config/system/index.vue +256 -0
  31. package/views/config/system/meta.json +4 -0
  32. package/views/index/index.vue +46 -9
  33. package/views/index/meta.json +4 -0
  34. package/views/log/email/index.vue +285 -0
  35. package/views/log/email/meta.json +4 -0
  36. package/views/log/login/index.vue +180 -0
  37. package/views/log/login/meta.json +4 -0
  38. package/views/log/meta.json +4 -0
  39. package/views/log/operate/index.vue +242 -0
  40. package/views/log/operate/meta.json +4 -0
  41. package/views/login_1/meta.json +4 -0
  42. package/views/{admin → people/admin}/components/edit.vue +22 -24
  43. package/views/{admin → people/admin}/index.vue +21 -61
  44. package/views/people/admin/meta.json +4 -0
  45. package/views/people/meta.json +4 -0
  46. package/views/{api → permission/api}/index.vue +17 -55
  47. package/views/permission/api/meta.json +4 -0
  48. package/views/{menu → permission/menu}/index.vue +17 -56
  49. package/views/permission/menu/meta.json +4 -0
  50. package/views/permission/meta.json +4 -0
  51. package/views/{role → permission/role}/components/api.vue +13 -38
  52. package/views/{role → permission/role}/components/edit.vue +9 -8
  53. package/views/{role → permission/role}/components/menu.vue +2 -25
  54. package/views/{role → permission/role}/index.vue +27 -36
  55. package/views/permission/role/meta.json +4 -0
  56. /package/views/{403 → 403_1}/index.vue +0 -0
  57. /package/views/{dict → config/dict}/components/edit.vue +0 -0
  58. /package/views/{login → login_1}/components/emailLoginForm.vue +0 -0
  59. /package/views/{login → login_1}/components/registerForm.vue +0 -0
  60. /package/views/{login → login_1}/components/welcomePanel.vue +0 -0
  61. /package/views/{login/index_1.vue → login_1/index.vue} +0 -0
@@ -13,7 +13,7 @@
13
13
 
14
14
  <div class="main-content">
15
15
  <div class="main-table">
16
- <TTable v-bind="withTreeTableProps()" :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :selected-row-keys="$Data.selectedRowKeys" :active-row-keys="$Data.activeRowKeys" @select-change="$Method.onSelectChange" @active-change="$Method.onActiveChange">
16
+ <TTable v-bind="withTreeTableProps()" :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="calc(100vh - 94px)" active-row-type="single" @active-change="$Method.onActiveChange">
17
17
  <template #state="{ row }">
18
18
  <TTag v-if="row.state === 1" shape="round" theme="success" variant="light-outline">正常</TTag>
19
19
  <TTag v-else-if="row.state === 2" shape="round" theme="warning" variant="light-outline">禁用</TTag>
@@ -23,18 +23,7 @@
23
23
  </div>
24
24
 
25
25
  <div class="main-detail">
26
- <DetailPanel
27
- :data="$Data.currentRow"
28
- :fields="[
29
- { key: 'id', label: 'ID' },
30
- { key: 'name', label: '菜单名称' },
31
- { key: 'path', label: '路由路径' },
32
- { key: 'icon', label: '图标' },
33
- { key: 'sort', label: '排序' },
34
- { key: 'pid', label: '父级ID', default: '顶级菜单' },
35
- { key: 'state', label: '状态' }
36
- ]"
37
- />
26
+ <DetailPanel :data="$Data.currentRow" :fields="$Data.columns" />
38
27
  </div>
39
28
  </div>
40
29
  </div>
@@ -52,23 +41,14 @@ const $Data = $ref({
52
41
  tableData: [],
53
42
  loading: false,
54
43
  columns: withDefaultColumns([
55
- {
56
- colKey: 'row-select',
57
- type: 'single',
58
- width: 50,
59
- fixed: 'left',
60
- checkProps: { allowUncheck: true },
61
- ellipsis: false
62
- },
63
- { colKey: 'name', title: '菜单名称', width: 200, fixed: 'left' },
64
- { colKey: 'id', title: '序号', width: 100, align: 'center' },
65
- { colKey: 'path', title: '路由路径', width: 250 },
66
- { colKey: 'icon', title: '图标', width: 120 },
67
- { colKey: 'sort', title: '排序', width: 80, align: 'center' },
68
- { colKey: 'state', title: '状态', width: 100, ellipsis: false }
44
+ { colKey: 'name', title: '菜单名称', fixed: 'left' },
45
+ { colKey: 'id', title: '序号' },
46
+ { colKey: 'path', title: '路由路径' },
47
+ { colKey: 'icon', title: '图标' },
48
+ { colKey: 'sort', title: '排序' },
49
+ { colKey: 'state', title: '状态' }
69
50
  ]),
70
51
  currentRow: null,
71
- selectedRowKeys: [],
72
52
  activeRowKeys: []
73
53
  });
74
54
 
@@ -86,14 +66,12 @@ const $Method = {
86
66
  // 构建树形结构
87
67
  $Data.tableData = $Method.buildTree(res.data || []);
88
68
 
89
- // 自动选中并高亮第一行
69
+ // 自动高亮第一行
90
70
  if ($Data.tableData.length > 0) {
91
71
  $Data.currentRow = $Data.tableData[0];
92
- $Data.selectedRowKeys = [$Data.tableData[0].id];
93
72
  $Data.activeRowKeys = [$Data.tableData[0].id];
94
73
  } else {
95
74
  $Data.currentRow = null;
96
- $Data.selectedRowKeys = [];
97
75
  $Data.activeRowKeys = [];
98
76
  }
99
77
  } catch (error) {
@@ -146,33 +124,16 @@ const $Method = {
146
124
  $Method.apiMenuList();
147
125
  },
148
126
 
149
- // 单选变化
150
- onSelectChange(value, { selectedRowData }) {
151
- $Data.selectedRowKeys = value;
152
- $Data.activeRowKeys = value;
153
- if (selectedRowData && selectedRowData.length > 0) {
154
- $Data.currentRow = selectedRowData[0];
155
- } else if ($Data.tableData.length > 0) {
156
- $Data.currentRow = $Data.tableData[0];
157
- $Data.selectedRowKeys = [$Data.tableData[0].id];
158
- $Data.activeRowKeys = [$Data.tableData[0].id];
159
- } else {
160
- $Data.currentRow = null;
161
- }
162
- },
163
-
164
127
  // 高亮行变化
165
- onActiveChange(value, { activeRowData }) {
128
+ onActiveChange(value, context) {
129
+ // 禁止取消高亮:如果新值为空,保持当前选中
130
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
131
+ return;
132
+ }
166
133
  $Data.activeRowKeys = value;
167
- $Data.selectedRowKeys = value;
168
- if (activeRowData && activeRowData.length > 0) {
169
- $Data.currentRow = activeRowData[0];
170
- } else if ($Data.tableData.length > 0) {
171
- $Data.currentRow = $Data.tableData[0];
172
- $Data.selectedRowKeys = [$Data.tableData[0].id];
173
- $Data.activeRowKeys = [$Data.tableData[0].id];
174
- } else {
175
- $Data.currentRow = null;
134
+ // 更新当前高亮的行数据
135
+ if (context.activeRowList && context.activeRowList.length > 0) {
136
+ $Data.currentRow = context.activeRowList[0].row;
176
137
  }
177
138
  }
178
139
  };
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "菜单列表",
3
+ "order": 2
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "权限设置",
3
+ "order": 20
4
+ }
@@ -12,7 +12,7 @@
12
12
 
13
13
  <!-- 接口分组列表 -->
14
14
  <div class="api-container">
15
- <div v-for="group in $Data.filteredApiData" :key="group.name" class="api-group">
15
+ <div class="api-group" v-for="group in $Data.filteredApiData" :key="group.name">
16
16
  <div class="group-header">{{ group.title }}</div>
17
17
  <div class="api-checkbox-list">
18
18
  <TCheckboxGroup v-model="$Data.checkedApiIds">
@@ -24,13 +24,11 @@
24
24
  </div>
25
25
 
26
26
  <template #footer>
27
- <div class="footer-left">
28
- <TButton size="small" @click="$Method.onCheckAll">全选</TButton>
29
- <TButton size="small" @click="$Method.onUncheckAll">取消全选</TButton>
30
- </div>
31
- <div class="footer-right">
32
- <TButton @click="$Method.onClose">取消</TButton>
33
- <TButton theme="primary" :loading="$Data.submitting" @click="$Method.onSubmit">保存</TButton>
27
+ <div class="dialog-footer">
28
+ <t-space>
29
+ <TButton theme="default" @click="$Method.onClose">取消</TButton>
30
+ <TButton theme="primary" :loading="$Data.submitting" @click="$Method.onSubmit">保存</TButton>
31
+ </t-space>
34
32
  </div>
35
33
  </template>
36
34
  </TDialog>
@@ -149,22 +147,6 @@ const $Method = {
149
147
  .filter((group) => group.apis.length > 0);
150
148
  },
151
149
 
152
- // 全选
153
- onCheckAll() {
154
- const allApiIds = [];
155
- $Data.apiData.forEach((group) => {
156
- group.apis.forEach((api) => {
157
- allApiIds.push(api.id);
158
- });
159
- });
160
- $Data.checkedApiIds = allApiIds;
161
- },
162
-
163
- // 取消全选
164
- onUncheckAll() {
165
- $Data.checkedApiIds = [];
166
- },
167
-
168
150
  // 提交表单
169
151
  async onSubmit() {
170
152
  try {
@@ -214,6 +196,10 @@ $Method.initData();
214
196
  border-radius: var(--border-radius-small);
215
197
  overflow: hidden;
216
198
 
199
+ .api-checkbox-list {
200
+ padding: 10px;
201
+ }
202
+
217
203
  &:last-child {
218
204
  margin-bottom: 0;
219
205
  }
@@ -267,20 +253,9 @@ $Method.initData();
267
253
  }
268
254
  }
269
255
 
270
- // 底部操作栏布局
271
- :deep(.t-dialog__footer) {
256
+ .dialog-footer {
257
+ width: 100%;
272
258
  display: flex;
273
- justify-content: space-between;
274
- align-items: center;
275
-
276
- .footer-left {
277
- display: flex;
278
- gap: 8px;
279
- }
280
-
281
- .footer-right {
282
- display: flex;
283
- gap: 8px;
284
- }
259
+ justify-content: center;
285
260
  }
286
261
  </style>
@@ -9,15 +9,15 @@
9
9
  <TInput v-model="$Data.formData.code" placeholder="请输入角色代码,如:admin" />
10
10
  </TFormItem>
11
11
  <TFormItem label="角色描述" prop="description">
12
- <TInput v-model="$Data.formData.description" type="textarea" placeholder="请输入角色描述" :rows="3" />
12
+ <TInput v-model="$Data.formData.description" placeholder="请输入角色描述" />
13
13
  </TFormItem>
14
14
  <TFormItem label="排序" prop="sort">
15
15
  <TInputNumber v-model="$Data.formData.sort" :min="0" :max="9999" />
16
16
  </TFormItem>
17
17
  <TFormItem label="状态" prop="state">
18
18
  <TRadioGroup v-model="$Data.formData.state">
19
- <TRadio :label="1">正常</TRadio>
20
- <TRadio :label="2">禁用</TRadio>
19
+ <TRadio :value="1">正常</TRadio>
20
+ <TRadio :value="2">禁用</TRadio>
21
21
  </TRadioGroup>
22
22
  </TFormItem>
23
23
  </TForm>
@@ -42,6 +42,7 @@ import {
42
42
  Button as TButton,
43
43
  MessagePlugin
44
44
  } from 'tdesign-vue-next';
45
+ import { fieldClear } from 'befly-shared/fieldClear';
45
46
  import { $Http } from '@/plugins/http';
46
47
 
47
48
  const $Prop = defineProps({
@@ -118,14 +119,14 @@ const $Method = {
118
119
  if (!valid) return;
119
120
 
120
121
  $Data.submitting = true;
121
- const res = await $Http($Prop.actionType === 'upd' ? '/addon/admin/roleUpd' : '/addon/admin/roleIns', $Data.formData);
122
+ const formData = $Prop.actionType === 'add' ? fieldClear($Data.formData, { omitKeys: ['id', 'state'] }) : $Data.formData;
123
+ const res = await $Http($Prop.actionType === 'upd' ? '/addon/admin/role/upd' : '/addon/admin/role/ins', formData);
122
124
 
123
- MessagePlugin.success($Prop.actionType === 'upd' ? '更新成功' : '添加成功');
124
- $Data.visible = false;
125
+ MessagePlugin.success(res.msg);
125
126
  $Emit('success');
127
+ $Method.onClose();
126
128
  } catch (error) {
127
- console.error('提交失败:', error);
128
- MessagePlugin.error('提交失败');
129
+ MessagePlugin.error(error.msg || '提交失败');
129
130
  } finally {
130
131
  $Data.submitting = false;
131
132
  }
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <TDialog v-model:visible="$Data.visible" title="菜单权限" width="600px" :append-to-body="true" :show-footer="true" top="10vh" @close="$Method.onClose">
3
3
  <div class="comp-role-menu">
4
- <TTree :data="$Data.menuTreeData" node-key="id" show-checkbox default-expand-all :props="{ label: 'name' }" :ref="(el) => ($From.tree = el)" />
4
+ <TTree v-model:value="$Data.menuTreeCheckedKeys" :data="$Data.menuTreeData" value-mode="all" :keys="{ value: 'id', label: 'name', children: 'children' }" checkable expand-all />
5
5
  </div>
6
6
  <template #footer>
7
7
  <TButton @click="$Method.onClose">取消</TButton>
@@ -11,7 +11,6 @@
11
11
  </template>
12
12
 
13
13
  <script setup>
14
- import { nextTick } from 'vue';
15
14
  import { Dialog as TDialog, Tree as TTree, Button as TButton, MessagePlugin } from 'tdesign-vue-next';
16
15
  import { arrayToTree } from '@/utils';
17
16
  import { $Http } from '@/plugins/http';
@@ -29,11 +28,6 @@ const $Prop = defineProps({
29
28
 
30
29
  const $Emit = defineEmits(['update:modelValue', 'success']);
31
30
 
32
- // 表单引用
33
- const $From = $shallowRef({
34
- tree: null
35
- });
36
-
37
31
  const $Data = $ref({
38
32
  visible: false,
39
33
  submitting: false,
@@ -85,13 +79,6 @@ const $Method = {
85
79
 
86
80
  // roleMenuDetail 返回的 data 直接就是菜单 ID 数组
87
81
  $Data.menuTreeCheckedKeys = Array.isArray(res.data) ? res.data : [];
88
-
89
- // 等待树渲染完成后设置选中状态
90
- nextTick(() => {
91
- if ($From.tree && $Data.menuTreeCheckedKeys.length > 0) {
92
- $From.tree.setCheckedKeys($Data.menuTreeCheckedKeys);
93
- }
94
- });
95
82
  } catch (error) {
96
83
  console.error('加载角色菜单失败:', error);
97
84
  }
@@ -100,21 +87,11 @@ const $Method = {
100
87
  // 提交表单
101
88
  async onSubmit() {
102
89
  try {
103
- if (!$From.tree) {
104
- MessagePlugin.error('菜单树未初始化');
105
- return;
106
- }
107
-
108
90
  $Data.submitting = true;
109
91
 
110
- // 获取选中的节点(包括半选中的父节点)
111
- const checkedKeys = $From.tree.getCheckedKeys();
112
- const halfCheckedKeys = $From.tree.getHalfCheckedKeys();
113
- const menuIds = [...checkedKeys, ...halfCheckedKeys];
114
-
115
92
  const res = await $Http('/addon/admin/role/menuSave', {
116
93
  roleId: $Prop.rowData.id,
117
- menuIds
94
+ menuIds: $Data.menuTreeCheckedKeys
118
95
  });
119
96
 
120
97
  if (res.code === 0) {
@@ -9,7 +9,7 @@
9
9
  </TButton>
10
10
  </div>
11
11
  <div class="right">
12
- <TButton @click="$Method.handleRefresh">
12
+ <TButton shape="circle" @click="$Method.handleRefresh">
13
13
  <template #icon>
14
14
  <ILucideRotateCw />
15
15
  </template>
@@ -18,15 +18,18 @@
18
18
  </div>
19
19
  <div class="main-content">
20
20
  <div class="main-table">
21
- <TTable v-bind="withTableProps()" :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" @active-change="$Method.onActiveChange">
21
+ <TTable :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="calc(100vh - 94px)" active-row-type="single" @active-change="$Method.onActiveChange">
22
22
  <template #state="{ row }">
23
- <TTag v-if="row.state === 1" theme="success">正常</TTag>
24
- <TTag v-else-if="row.state === 2" theme="warning">禁用</TTag>
25
- <TTag v-else theme="danger">已删除</TTag>
23
+ <TTag v-if="row.state === 1" shape="round" theme="success" variant="light-outline">正常</TTag>
24
+ <TTag v-else-if="row.state === 2" shape="round" theme="warning" variant="light-outline">禁用</TTag>
25
+ <TTag v-else shape="round" theme="danger" variant="light-outline">已删除</TTag>
26
26
  </template>
27
27
  <template #operation="{ row }">
28
- <TDropdown trigger="click" min-column-width="120" @click="(data) => $Method.onAction(data.value, row)">
29
- <TButton variant="text" size="small">操作</TButton>
28
+ <TDropdown trigger="click" placement="bottom-right" @click="(data) => $Method.onAction(data.value, row)">
29
+ <TButton theme="primary" size="small">
30
+ 操作
31
+ <template #suffix> <t-icon name="chevron-down" size="16" /></template>
32
+ </TButton>
30
33
  <TDropdownMenu slot="dropdown">
31
34
  <TDropdownItem value="upd">
32
35
  <ILucidePencil />
@@ -51,17 +54,7 @@
51
54
  </div>
52
55
 
53
56
  <div class="main-detail">
54
- <DetailPanel
55
- :data="$Data.currentRow"
56
- :fields="[
57
- { key: 'id', label: 'ID' },
58
- { key: 'name', label: '角色名称' },
59
- { key: 'code', label: '角色代码' },
60
- { key: 'description', label: '描述' },
61
- { key: 'sort', label: '排序' },
62
- { key: 'state', label: '状态' }
63
- ]"
64
- />
57
+ <DetailPanel :data="$Data.currentRow" :fields="$Data.columns" />
65
58
  </div>
66
59
  </div>
67
60
 
@@ -93,7 +86,7 @@ import MenuDialog from './components/menu.vue';
93
86
  import ApiDialog from './components/api.vue';
94
87
  import DetailPanel from '@/components/DetailPanel.vue';
95
88
  import { $Http } from '@/plugins/http';
96
- import { withDefaultColumns, withTableProps } from '@/utils';
89
+ import { withDefaultColumns } from '@/utils';
97
90
 
98
91
  // 响应式数据
99
92
  const $Data = $ref({
@@ -102,13 +95,13 @@ const $Data = $ref({
102
95
  activeRowKeys: [],
103
96
  currentRow: null,
104
97
  columns: withDefaultColumns([
105
- { colKey: 'index', title: '序号', width: 100, align: 'center' },
106
- { colKey: 'name', title: '角色名称', width: 150 },
107
- { colKey: 'code', title: '角色代码', width: 150 },
108
- { colKey: 'description', title: '描述', minWidth: 150 },
109
- { colKey: 'sort', title: '排序', width: 80, align: 'center' },
110
- { colKey: 'state', title: '状态', width: 100, align: 'center', ellipsis: false },
111
- { colKey: 'operation', title: '操作', width: 120, align: 'center', fixed: 'right', ellipsis: false }
98
+ { colKey: 'id', title: 'ID' },
99
+ { colKey: 'name', title: '角色名称' },
100
+ { colKey: 'code', title: '角色代码' },
101
+ { colKey: 'description', title: '描述' },
102
+ { colKey: 'sort', title: '排序' },
103
+ { colKey: 'state', title: '状态' },
104
+ { colKey: 'operation', title: '操作' }
112
105
  ]),
113
106
  pagerConfig: {
114
107
  currentPage: 1,
@@ -196,18 +189,16 @@ const $Method = {
196
189
  $Method.apiRoleList();
197
190
  },
198
191
 
199
- // 高亮行变化(点击行选中)
200
- onActiveChange(value, { activeRowData }) {
192
+ // 高亮行变化
193
+ onActiveChange(value, context) {
194
+ // 禁止取消高亮:如果新值为空,保持当前选中
195
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
196
+ return;
197
+ }
201
198
  $Data.activeRowKeys = value;
202
199
  // 更新当前高亮的行数据
203
- if (activeRowData && activeRowData.length > 0) {
204
- $Data.currentRow = activeRowData[0];
205
- } else if ($Data.tableData.length > 0) {
206
- // 如果取消高亮,默认显示第一行
207
- $Data.currentRow = $Data.tableData[0];
208
- $Data.activeRowKeys = [$Data.tableData[0].id];
209
- } else {
210
- $Data.currentRow = null;
200
+ if (context.activeRowList && context.activeRowList.length > 0) {
201
+ $Data.currentRow = context.activeRowList[0].row;
211
202
  }
212
203
  },
213
204
 
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "角色管理",
3
+ "order": 1
4
+ }
File without changes
File without changes
File without changes