@befly-addon/admin 1.0.54 → 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 (82) hide show
  1. package/apis/admin/cacheRefresh.ts +17 -14
  2. package/apis/admin/ins.ts +11 -15
  3. package/apis/admin/upd.ts +1 -13
  4. package/apis/api/all.ts +1 -1
  5. package/apis/api/list.ts +30 -0
  6. package/apis/auth/login.ts +51 -7
  7. package/apis/dashboard/serviceStatus.ts +2 -2
  8. package/apis/dashboard/systemResources.ts +1 -1
  9. package/apis/dict/all.ts +1 -1
  10. package/apis/dict/del.ts +1 -1
  11. package/apis/dict/detail.ts +2 -2
  12. package/apis/dict/ins.ts +1 -1
  13. package/apis/dict/upd.ts +1 -1
  14. package/apis/email/config.ts +16 -0
  15. package/apis/email/logList.ts +13 -0
  16. package/apis/email/send.ts +42 -0
  17. package/apis/email/verify.ts +12 -0
  18. package/apis/loginLog/list.ts +13 -0
  19. package/apis/menu/all.ts +2 -2
  20. package/apis/menu/list.ts +1 -1
  21. package/apis/operateLog/list.ts +13 -0
  22. package/apis/role/del.ts +2 -2
  23. package/apis/role/save.ts +2 -2
  24. package/apis/sysConfig/all.ts +12 -0
  25. package/apis/sysConfig/del.ts +30 -0
  26. package/apis/sysConfig/get.ts +31 -0
  27. package/apis/sysConfig/ins.ts +38 -0
  28. package/apis/sysConfig/list.ts +14 -0
  29. package/apis/sysConfig/upd.ts +50 -0
  30. package/package.json +14 -3
  31. package/plugins/email.ts +206 -0
  32. package/styles/variables.scss +121 -60
  33. package/tables/admin.json +0 -15
  34. package/tables/emailLog.json +69 -0
  35. package/tables/loginLog.json +96 -0
  36. package/tables/operateLog.json +82 -0
  37. package/tables/role.json +1 -1
  38. package/tables/sysConfig.json +53 -0
  39. package/views/403_1/meta.json +4 -0
  40. package/views/{dict → config/dict}/components/edit.vue +7 -5
  41. package/views/config/dict/index.vue +205 -0
  42. package/views/config/dict/meta.json +4 -0
  43. package/views/config/meta.json +4 -0
  44. package/views/config/system/components/edit.vue +179 -0
  45. package/views/config/system/index.vue +256 -0
  46. package/views/config/system/meta.json +4 -0
  47. package/views/index/index.vue +46 -9
  48. package/views/index/meta.json +4 -0
  49. package/views/log/email/index.vue +285 -0
  50. package/views/log/email/meta.json +4 -0
  51. package/views/log/login/index.vue +180 -0
  52. package/views/log/login/meta.json +4 -0
  53. package/views/log/meta.json +4 -0
  54. package/views/log/operate/index.vue +242 -0
  55. package/views/log/operate/meta.json +4 -0
  56. package/views/login_1/meta.json +4 -0
  57. package/views/{admin → people/admin}/components/edit.vue +23 -35
  58. package/views/{admin → people/admin}/index.vue +37 -96
  59. package/views/people/admin/meta.json +4 -0
  60. package/views/people/meta.json +4 -0
  61. package/views/permission/api/index.vue +143 -0
  62. package/views/permission/api/meta.json +4 -0
  63. package/views/permission/menu/index.vue +146 -0
  64. package/views/permission/menu/meta.json +4 -0
  65. package/views/permission/meta.json +4 -0
  66. package/views/{role → permission/role}/components/api.vue +22 -51
  67. package/views/{role → permission/role}/components/edit.vue +14 -15
  68. package/views/{role → permission/role}/components/menu.vue +11 -38
  69. package/views/permission/role/index.vue +227 -0
  70. package/views/permission/role/meta.json +4 -0
  71. package/apis/menu/del.ts +0 -31
  72. package/apis/menu/ins.ts +0 -19
  73. package/apis/menu/upd.ts +0 -27
  74. package/views/dict/index.vue +0 -162
  75. package/views/menu/components/edit.vue +0 -145
  76. package/views/menu/index.vue +0 -173
  77. package/views/role/index.vue +0 -184
  78. /package/views/{403 → 403_1}/index.vue +0 -0
  79. /package/views/{login → login_1}/components/emailLoginForm.vue +0 -0
  80. /package/views/{login → login_1}/components/registerForm.vue +0 -0
  81. /package/views/{login → login_1}/components/welcomePanel.vue +0 -0
  82. /package/views/{login/index_1.vue → login_1/index.vue} +0 -0
@@ -0,0 +1,180 @@
1
+ <template>
2
+ <div class="page-login-log 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 :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="100%" active-row-type="single" @active-change="$Method.onActiveChange">
17
+ <template #loginResult="{ row }">
18
+ <TTag v-if="row.loginResult === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
19
+ <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
20
+ </template>
21
+ <template #loginTime="{ row }">
22
+ {{ $Method.formatTime(row.loginTime) }}
23
+ </template>
24
+ <template #deviceType="{ row }">
25
+ <TTag shape="round" variant="light-outline">{{ row.deviceType || 'desktop' }}</TTag>
26
+ </template>
27
+ </TTable>
28
+ </div>
29
+
30
+ <div class="main-detail">
31
+ <DetailPanel :data="$Data.currentRow" :fields="$Data.detailFields">
32
+ <template #loginResult="{ value }">
33
+ <TTag v-if="value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
34
+ <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
35
+ </template>
36
+ <template #loginTime="{ value }">
37
+ {{ $Method.formatTime(value) }}
38
+ </template>
39
+ <template #deviceType="{ value }">
40
+ <TTag shape="round" variant="light-outline">{{ value || 'desktop' }}</TTag>
41
+ </template>
42
+ </DetailPanel>
43
+ </div>
44
+ </div>
45
+
46
+ <div class="main-page">
47
+ <TPagination :current-page="$Data.pagerConfig.currentPage" :page-size="$Data.pagerConfig.limit" :total="$Data.pagerConfig.total" @current-change="$Method.onPageChange" @page-size-change="$Method.handleSizeChange" />
48
+ </div>
49
+ </div>
50
+ </template>
51
+
52
+ <script setup>
53
+ import { Button as TButton, Table as TTable, Tag as TTag, Pagination as TPagination, MessagePlugin } from 'tdesign-vue-next';
54
+ import ILucideRotateCw from '~icons/lucide/rotate-cw';
55
+ import DetailPanel from '@/components/DetailPanel.vue';
56
+ import { $Http } from '@/plugins/http';
57
+ import { withDefaultColumns } from '@/utils';
58
+
59
+ // 响应式数据
60
+ const $Data = $ref({
61
+ tableData: [],
62
+ loading: false,
63
+ columns: withDefaultColumns([
64
+ { colKey: 'username', title: '用户名', fixed: 'left' },
65
+ { colKey: 'id', title: '序号' },
66
+ { colKey: 'ip', title: '登录IP' },
67
+ { colKey: 'browserName', title: '浏览器' },
68
+ { colKey: 'osName', title: '操作系统' },
69
+ { colKey: 'deviceType', title: '设备类型' },
70
+ { colKey: 'loginTime', title: '登录时间' },
71
+ { colKey: 'loginResult', title: '登录结果' }
72
+ ]),
73
+ // 详情面板显示更多字段
74
+ detailFields: [
75
+ { colKey: 'username', title: '用户名' },
76
+ { colKey: 'nickname', title: '昵称' },
77
+ { colKey: 'ip', title: '登录IP' },
78
+ { colKey: 'browserName', title: '浏览器' },
79
+ { colKey: 'browserVersion', title: '浏览器版本' },
80
+ { colKey: 'osName', title: '操作系统' },
81
+ { colKey: 'osVersion', title: '系统版本' },
82
+ { colKey: 'deviceType', title: '设备类型' },
83
+ { colKey: 'deviceVendor', title: '设备厂商' },
84
+ { colKey: 'deviceModel', title: '设备型号' },
85
+ { colKey: 'engineName', title: '渲染引擎' },
86
+ { colKey: 'cpuArchitecture', title: 'CPU架构' },
87
+ { colKey: 'loginTime', title: '登录时间' },
88
+ { colKey: 'loginResult', title: '登录结果' },
89
+ { colKey: 'failReason', title: '失败原因' }
90
+ ],
91
+ pagerConfig: {
92
+ currentPage: 1,
93
+ limit: 30,
94
+ total: 0
95
+ },
96
+ currentRow: null,
97
+ activeRowKeys: []
98
+ });
99
+
100
+ // 方法
101
+ const $Method = {
102
+ async initData() {
103
+ await $Method.apiLoginLogList();
104
+ },
105
+
106
+ // 加载登录日志列表
107
+ async apiLoginLogList() {
108
+ $Data.loading = true;
109
+ try {
110
+ const res = await $Http('/addon/admin/loginLog/list', {
111
+ page: $Data.pagerConfig.currentPage,
112
+ limit: $Data.pagerConfig.limit
113
+ });
114
+ $Data.tableData = res.data.lists || [];
115
+ $Data.pagerConfig.total = res.data.total || 0;
116
+
117
+ // 自动高亮第一行
118
+ if ($Data.tableData.length > 0) {
119
+ $Data.currentRow = $Data.tableData[0];
120
+ $Data.activeRowKeys = [$Data.tableData[0].id];
121
+ } else {
122
+ $Data.currentRow = null;
123
+ $Data.activeRowKeys = [];
124
+ }
125
+ } catch (error) {
126
+ MessagePlugin.error('加载数据失败');
127
+ } finally {
128
+ $Data.loading = false;
129
+ }
130
+ },
131
+
132
+ // 刷新
133
+ handleRefresh() {
134
+ $Method.apiLoginLogList();
135
+ },
136
+
137
+ // 分页改变
138
+ onPageChange(currentPage) {
139
+ $Data.pagerConfig.currentPage = currentPage;
140
+ $Method.apiLoginLogList();
141
+ },
142
+
143
+ // 每页条数改变
144
+ handleSizeChange(pageSize) {
145
+ $Data.pagerConfig.limit = pageSize;
146
+ $Data.pagerConfig.currentPage = 1;
147
+ $Method.apiLoginLogList();
148
+ },
149
+
150
+ // 高亮行变化
151
+ onActiveChange(value, context) {
152
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
153
+ return;
154
+ }
155
+ $Data.activeRowKeys = value;
156
+ if (context.activeRowList && context.activeRowList.length > 0) {
157
+ $Data.currentRow = context.activeRowList[0].row;
158
+ }
159
+ },
160
+
161
+ // 格式化时间
162
+ formatTime(timestamp) {
163
+ if (!timestamp) return '-';
164
+ const date = new Date(timestamp);
165
+ const year = date.getFullYear();
166
+ const month = String(date.getMonth() + 1).padStart(2, '0');
167
+ const day = String(date.getDate()).padStart(2, '0');
168
+ const hours = String(date.getHours()).padStart(2, '0');
169
+ const minutes = String(date.getMinutes()).padStart(2, '0');
170
+ const seconds = String(date.getSeconds()).padStart(2, '0');
171
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
172
+ }
173
+ };
174
+
175
+ $Method.initData();
176
+ </script>
177
+
178
+ <style scoped lang="scss">
179
+ // 样式继承自全局 page-table
180
+ </style>
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "登录日志",
3
+ "order": 1
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "日志管理",
3
+ "order": 40
4
+ }
@@ -0,0 +1,242 @@
1
+ <template>
2
+ <div class="page-operate-log page-table">
3
+ <div class="main-tool">
4
+ <div class="left">
5
+ <TSelect v-model="$Data.filter.module" placeholder="操作模块" clearable style="width: 150px" @change="$Method.handleFilter">
6
+ <TOption v-for="item in $Data.moduleOptions" :key="item.value" :label="item.label" :value="item.value" />
7
+ </TSelect>
8
+ <TSelect v-model="$Data.filter.action" placeholder="操作类型" clearable style="width: 150px" @change="$Method.handleFilter">
9
+ <TOption v-for="item in $Data.actionOptions" :key="item.value" :label="item.label" :value="item.value" />
10
+ </TSelect>
11
+ <TSelect v-model="$Data.filter.result" placeholder="操作结果" clearable style="width: 120px" @change="$Method.handleFilter">
12
+ <TOption label="成功" :value="1" />
13
+ <TOption label="失败" :value="0" />
14
+ </TSelect>
15
+ </div>
16
+ <div class="right">
17
+ <TButton shape="circle" @click="$Method.handleRefresh">
18
+ <template #icon>
19
+ <ILucideRotateCw />
20
+ </template>
21
+ </TButton>
22
+ </div>
23
+ </div>
24
+
25
+ <div class="main-content">
26
+ <div class="main-table">
27
+ <TTable :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="100%" active-row-type="single" @active-change="$Method.onActiveChange">
28
+ <template #result="{ row }">
29
+ <TTag v-if="row.result === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
30
+ <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
31
+ </template>
32
+ <template #operateTime="{ row }">
33
+ {{ $Method.formatTime(row.operateTime) }}
34
+ </template>
35
+ <template #duration="{ row }">
36
+ <TTag shape="round" :theme="row.duration > 1000 ? 'warning' : 'default'" variant="light-outline">{{ row.duration }}ms</TTag>
37
+ </template>
38
+ <template #action="{ row }">
39
+ <TTag shape="round" variant="light-outline">{{ row.action }}</TTag>
40
+ </template>
41
+ </TTable>
42
+ </div>
43
+
44
+ <div class="main-detail">
45
+ <DetailPanel :data="$Data.currentRow" :fields="$Data.detailFields">
46
+ <template #result="{ value }">
47
+ <TTag v-if="value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
48
+ <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
49
+ </template>
50
+ <template #operateTime="{ value }">
51
+ {{ $Method.formatTime(value) }}
52
+ </template>
53
+ <template #duration="{ value }">
54
+ <TTag shape="round" :theme="value > 1000 ? 'warning' : 'default'" variant="light-outline">{{ value }}ms</TTag>
55
+ </template>
56
+ <template #params="{ value }">
57
+ <pre class="json-content">{{ $Method.formatJson(value) }}</pre>
58
+ </template>
59
+ <template #response="{ value }">
60
+ <pre class="json-content">{{ $Method.formatJson(value) }}</pre>
61
+ </template>
62
+ </DetailPanel>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="main-page">
67
+ <TPagination :current-page="$Data.pagerConfig.currentPage" :page-size="$Data.pagerConfig.limit" :total="$Data.pagerConfig.total" @current-change="$Method.onPageChange" @page-size-change="$Method.handleSizeChange" />
68
+ </div>
69
+ </div>
70
+ </template>
71
+
72
+ <script setup>
73
+ import { Button as TButton, Table as TTable, Tag as TTag, Pagination as TPagination, Select as TSelect, Option as TOption, MessagePlugin } from 'tdesign-vue-next';
74
+ import ILucideRotateCw from '~icons/lucide/rotate-cw';
75
+ import DetailPanel from '@/components/DetailPanel.vue';
76
+ import { $Http } from '@/plugins/http';
77
+ import { withDefaultColumns } from '@/utils';
78
+
79
+ // 响应式数据
80
+ const $Data = $ref({
81
+ tableData: [],
82
+ loading: false,
83
+ columns: withDefaultColumns([
84
+ { colKey: 'username', title: '操作人', fixed: 'left', width: 100 },
85
+ { colKey: 'id', title: '序号', width: 80 },
86
+ { colKey: 'module', title: '模块', width: 100 },
87
+ { colKey: 'action', title: '操作', width: 80 },
88
+ { colKey: 'path', title: '请求路径', ellipsis: true },
89
+ { colKey: 'ip', title: 'IP地址', width: 130 },
90
+ { colKey: 'duration', title: '耗时', width: 100 },
91
+ { colKey: 'operateTime', title: '操作时间', width: 170 },
92
+ { colKey: 'result', title: '结果', width: 80 }
93
+ ]),
94
+ detailFields: [
95
+ { colKey: 'username', title: '操作人账号' },
96
+ { colKey: 'nickname', title: '操作人昵称' },
97
+ { colKey: 'module', title: '操作模块' },
98
+ { colKey: 'action', title: '操作类型' },
99
+ { colKey: 'method', title: '请求方法' },
100
+ { colKey: 'path', title: '请求路径' },
101
+ { colKey: 'ip', title: 'IP地址' },
102
+ { colKey: 'params', title: '请求参数' },
103
+ { colKey: 'response', title: '响应内容' },
104
+ { colKey: 'duration', title: '耗时' },
105
+ { colKey: 'operateTime', title: '操作时间' },
106
+ { colKey: 'result', title: '操作结果' },
107
+ { colKey: 'remark', title: '备注' }
108
+ ],
109
+ pagerConfig: {
110
+ currentPage: 1,
111
+ limit: 30,
112
+ total: 0
113
+ },
114
+ currentRow: null,
115
+ activeRowKeys: [],
116
+ filter: {
117
+ module: '',
118
+ action: '',
119
+ result: null
120
+ },
121
+ moduleOptions: [
122
+ { label: '管理员', value: '管理员' },
123
+ { label: '角色', value: '角色' },
124
+ { label: '菜单', value: '菜单' },
125
+ { label: '接口', value: '接口' },
126
+ { label: '字典', value: '字典' }
127
+ ],
128
+ actionOptions: [
129
+ { label: '新增', value: '新增' },
130
+ { label: '编辑', value: '编辑' },
131
+ { label: '删除', value: '删除' },
132
+ { label: '查询', value: '查询' }
133
+ ]
134
+ });
135
+
136
+ // 方法
137
+ const $Method = {
138
+ async initData() {
139
+ await $Method.apiOperateLogList();
140
+ },
141
+
142
+ // 加载操作日志列表
143
+ async apiOperateLogList() {
144
+ $Data.loading = true;
145
+ try {
146
+ const res = await $Http('/addon/admin/operateLog/list', {
147
+ page: $Data.pagerConfig.currentPage,
148
+ limit: $Data.pagerConfig.limit
149
+ });
150
+ $Data.tableData = res.data.lists || [];
151
+ $Data.pagerConfig.total = res.data.total || 0;
152
+
153
+ if ($Data.tableData.length > 0) {
154
+ $Data.currentRow = $Data.tableData[0];
155
+ $Data.activeRowKeys = [$Data.tableData[0].id];
156
+ } else {
157
+ $Data.currentRow = null;
158
+ $Data.activeRowKeys = [];
159
+ }
160
+ } catch (error) {
161
+ MessagePlugin.error('加载数据失败');
162
+ } finally {
163
+ $Data.loading = false;
164
+ }
165
+ },
166
+
167
+ // 筛选
168
+ handleFilter() {
169
+ $Data.pagerConfig.currentPage = 1;
170
+ $Method.apiOperateLogList();
171
+ },
172
+
173
+ // 刷新
174
+ handleRefresh() {
175
+ $Method.apiOperateLogList();
176
+ },
177
+
178
+ // 分页改变
179
+ onPageChange(currentPage) {
180
+ $Data.pagerConfig.currentPage = currentPage;
181
+ $Method.apiOperateLogList();
182
+ },
183
+
184
+ // 每页条数改变
185
+ handleSizeChange(pageSize) {
186
+ $Data.pagerConfig.limit = pageSize;
187
+ $Data.pagerConfig.currentPage = 1;
188
+ $Method.apiOperateLogList();
189
+ },
190
+
191
+ // 高亮行变化
192
+ onActiveChange(value, context) {
193
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
194
+ return;
195
+ }
196
+ $Data.activeRowKeys = value;
197
+ if (context.activeRowList && context.activeRowList.length > 0) {
198
+ $Data.currentRow = context.activeRowList[0].row;
199
+ }
200
+ },
201
+
202
+ // 格式化时间
203
+ formatTime(timestamp) {
204
+ if (!timestamp) return '-';
205
+ const date = new Date(timestamp);
206
+ const year = date.getFullYear();
207
+ const month = String(date.getMonth() + 1).padStart(2, '0');
208
+ const day = String(date.getDate()).padStart(2, '0');
209
+ const hours = String(date.getHours()).padStart(2, '0');
210
+ const minutes = String(date.getMinutes()).padStart(2, '0');
211
+ const seconds = String(date.getSeconds()).padStart(2, '0');
212
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
213
+ },
214
+
215
+ // 格式化 JSON
216
+ formatJson(value) {
217
+ if (!value) return '-';
218
+ try {
219
+ const obj = typeof value === 'string' ? JSON.parse(value) : value;
220
+ return JSON.stringify(obj, null, 2);
221
+ } catch {
222
+ return value;
223
+ }
224
+ }
225
+ };
226
+
227
+ $Method.initData();
228
+ </script>
229
+
230
+ <style scoped lang="scss">
231
+ .json-content {
232
+ margin: 0;
233
+ padding: 8px;
234
+ background: var(--td-bg-color-container);
235
+ border-radius: 4px;
236
+ font-size: 12px;
237
+ max-height: 200px;
238
+ overflow: auto;
239
+ white-space: pre-wrap;
240
+ word-break: break-all;
241
+ }
242
+ </style>
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "操作日志",
3
+ "order": 3
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "登录页",
3
+ "order": 100
4
+ }
@@ -3,23 +3,17 @@
3
3
  <div class="dialog-wrapper">
4
4
  <TForm :model="$Data.formData" label-width="80px" label-position="left" label-align="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
5
5
  <TFormItem label="角色" prop="roleId">
6
- <TSelect v-model="$Data.formData.roleId" :options="$Data.roleOptions" placeholder="请选择角色" />
6
+ <TSelect v-model="$Data.formData.roleId" :options="$Data.allRoleLists" :keys="$Data.keys" placeholder="请选择角色" />
7
7
  </TFormItem>
8
8
  <TFormItem label="用户名" prop="username">
9
9
  <TInput v-model="$Data.formData.username" placeholder="请输入用户名" :disabled="$Prop.actionType === 'upd'" />
10
10
  </TFormItem>
11
- <TFormItem label="邮箱" prop="email">
12
- <TInput v-model="$Data.formData.email" placeholder="请输入邮箱" />
13
- </TFormItem>
14
11
  <TFormItem v-if="$Prop.actionType === 'add'" label="密码" prop="password">
15
12
  <TInput v-model="$Data.formData.password" type="password" placeholder="请输入密码,至少6位" />
16
13
  </TFormItem>
17
14
  <TFormItem label="昵称" prop="nickname">
18
15
  <TInput v-model="$Data.formData.nickname" placeholder="请输入昵称" />
19
16
  </TFormItem>
20
- <TFormItem label="手机号" prop="phone">
21
- <TInput v-model="$Data.formData.phone" placeholder="请输入手机号" />
22
- </TFormItem>
23
17
  <TFormItem v-if="$Prop.actionType === 'upd'" label="状态" prop="state">
24
18
  <TRadioGroup v-model="$Data.formData.state">
25
19
  <TRadio :label="1">正常</TRadio>
@@ -32,7 +26,7 @@
32
26
  <div class="dialog-footer">
33
27
  <t-space>
34
28
  <TButton theme="default" @click="$Method.onClose">取消</TButton>
35
- <TButton theme="primary" @click="$Method.onSubmit">确定</TButton>
29
+ <TButton theme="primary" :loading="$Data.submitting" @click="$Method.onSubmit">确定</TButton>
36
30
  </t-space>
37
31
  </div>
38
32
  </template>
@@ -53,7 +47,7 @@ import {
53
47
  MessagePlugin
54
48
  } from 'tdesign-vue-next';
55
49
  import { $Http } from '@/plugins/http';
56
- import { fieldClear } from 'befly-util/fieldClear';
50
+ import { fieldClear } from 'befly-shared/fieldClear';
57
51
 
58
52
  const $Prop = defineProps({
59
53
  modelValue: {
@@ -79,16 +73,18 @@ const $From = $shallowRef({
79
73
 
80
74
  const $Data = $ref({
81
75
  visible: false,
82
- roleOptions: [],
76
+ submitting: false,
77
+ allRoleLists: [],
78
+ keys: {
79
+ label: 'name',
80
+ value: 'id'
81
+ },
83
82
  formData: {
84
- id: 0,
83
+ id: null,
85
84
  username: '',
86
- email: '',
87
85
  password: '',
88
- name: '',
89
86
  nickname: '',
90
- phone: '',
91
- roleId: 0,
87
+ roleId: null,
92
88
  state: 1
93
89
  }
94
90
  });
@@ -96,18 +92,12 @@ const $Data = $ref({
96
92
  const $Data2 = $shallowRef({
97
93
  formRules: {
98
94
  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
99
- email: [
100
- { required: true, message: '请输入邮箱', trigger: 'blur' },
101
- { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
102
- ],
103
95
  password: [
104
96
  { required: true, message: '请输入密码', trigger: 'blur' },
105
97
  { min: 6, message: '密码至少6位', trigger: 'blur' }
106
98
  ],
107
99
  roleId: [{ required: true, message: '请选择角色', trigger: 'change' }],
108
- name: [{ min: 2, max: 50, message: '姓名长度在 2 到 50 个字符', trigger: 'blur' }],
109
- nickname: [{ min: 2, max: 50, message: '昵称长度在 2 到 50 个字符', trigger: 'blur' }],
110
- phone: [{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }]
100
+ nickname: [{ min: 2, max: 50, message: '昵称长度在 2 到 50 个字符', trigger: 'blur' }]
111
101
  }
112
102
  });
113
103
 
@@ -115,9 +105,8 @@ const $Data2 = $shallowRef({
115
105
  const $Method = {
116
106
  async initData() {
117
107
  $Method.onShow();
118
- await $Method.loadRoles();
108
+ await $Method.apiRoleLists();
119
109
  if ($Prop.actionType === 'upd' && $Prop.rowData.id) {
120
- // 编辑模式:直接赋值
121
110
  $Data.formData = { ...$Prop.rowData };
122
111
  }
123
112
  },
@@ -135,17 +124,13 @@ const $Method = {
135
124
  }, 300);
136
125
  },
137
126
 
138
- async loadRoles() {
127
+ async apiRoleLists() {
139
128
  try {
140
129
  const result = await $Http('/addon/admin/role/all');
141
- $Data.roleOptions = result
142
- .filter((role) => role.state === 1)
143
- .map((role) => ({
144
- label: role.name,
145
- value: role.id
146
- }));
130
+ $Data.allRoleLists = result.data || [];
147
131
  } catch (error) {
148
- MessagePlugin.error(error.msg || '加载角色列表失败');
132
+ console.error('加载角色列表失败:', error);
133
+ MessagePlugin.error('加载角色列表失败');
149
134
  }
150
135
  },
151
136
 
@@ -154,15 +139,18 @@ const $Method = {
154
139
  const valid = await $From.form.validate();
155
140
  if (!valid) return;
156
141
 
157
- const submitData = $Prop.actionType === 'add' ? fieldClear($Data.formData, { omitKeys: ['id', 'state'] }) : fieldClear($Data.formData, { omitKeys: ['password'] });
142
+ $Data.submitting = true;
143
+ const formData = $Prop.actionType === 'add' ? fieldClear($Data.formData, { omitKeys: ['id', 'state'] }) : fieldClear($Data.formData, { omitKeys: ['password'] });
158
144
 
159
- await $Http($Prop.actionType === 'upd' ? '/addon/admin/admin/upd' : '/addon/admin/admin/ins', submitData);
145
+ const result = await $Http($Prop.actionType === 'upd' ? '/addon/admin/admin/upd' : '/addon/admin/admin/ins', formData);
160
146
 
161
- MessagePlugin.success($Prop.actionType === 'upd' ? '编辑成功' : '添加成功');
147
+ MessagePlugin.success(result.msg);
162
148
  $Emit('success');
163
149
  $Method.onClose();
164
150
  } catch (error) {
165
151
  MessagePlugin.error(error.msg || '提交失败');
152
+ } finally {
153
+ $Data.submitting = false;
166
154
  }
167
155
  }
168
156
  };