@befly-addon/admin 1.0.55 → 1.0.57

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 +12 -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
@@ -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.allRoleLists" 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>
@@ -81,15 +75,16 @@ const $Data = $ref({
81
75
  visible: false,
82
76
  submitting: false,
83
77
  allRoleLists: [],
78
+ keys: {
79
+ label: 'name',
80
+ value: 'id'
81
+ },
84
82
  formData: {
85
- id: 0,
83
+ id: null,
86
84
  username: '',
87
- email: '',
88
85
  password: '',
89
- name: '',
90
86
  nickname: '',
91
- phone: '',
92
- roleId: 0,
87
+ roleId: null,
93
88
  state: 1
94
89
  }
95
90
  });
@@ -97,18 +92,12 @@ const $Data = $ref({
97
92
  const $Data2 = $shallowRef({
98
93
  formRules: {
99
94
  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
100
- email: [
101
- { required: true, message: '请输入邮箱', trigger: 'blur' },
102
- { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
103
- ],
104
95
  password: [
105
96
  { required: true, message: '请输入密码', trigger: 'blur' },
106
97
  { min: 6, message: '密码至少6位', trigger: 'blur' }
107
98
  ],
108
99
  roleId: [{ required: true, message: '请选择角色', trigger: 'change' }],
109
- name: [{ min: 2, max: 50, message: '姓名长度在 2 到 50 个字符', trigger: 'blur' }],
110
- nickname: [{ min: 2, max: 50, message: '昵称长度在 2 到 50 个字符', trigger: 'blur' }],
111
- phone: [{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }]
100
+ nickname: [{ min: 2, max: 50, message: '昵称长度在 2 到 50 个字符', trigger: 'blur' }]
112
101
  }
113
102
  });
114
103
 
@@ -116,9 +105,8 @@ const $Data2 = $shallowRef({
116
105
  const $Method = {
117
106
  async initData() {
118
107
  $Method.onShow();
119
- $Data.allRoleLists = await $Http('/addon/admin/role/all');
108
+ await $Method.apiRoleLists();
120
109
  if ($Prop.actionType === 'upd' && $Prop.rowData.id) {
121
- // 编辑模式:直接赋值
122
110
  $Data.formData = { ...$Prop.rowData };
123
111
  }
124
112
  },
@@ -136,17 +124,27 @@ const $Method = {
136
124
  }, 300);
137
125
  },
138
126
 
127
+ async apiRoleLists() {
128
+ try {
129
+ const result = await $Http('/addon/admin/role/all');
130
+ $Data.allRoleLists = result.data || [];
131
+ } catch (error) {
132
+ console.error('加载角色列表失败:', error);
133
+ MessagePlugin.error('加载角色列表失败');
134
+ }
135
+ },
136
+
139
137
  async onSubmit() {
140
138
  try {
141
139
  const valid = await $From.form.validate();
142
140
  if (!valid) return;
143
141
 
144
142
  $Data.submitting = true;
145
- const submitData = $Prop.actionType === 'add' ? fieldClear($Data.formData, { omitKeys: ['id', 'state'] }) : fieldClear($Data.formData, { omitKeys: ['password'] });
143
+ const formData = $Prop.actionType === 'add' ? fieldClear($Data.formData, { omitKeys: ['id', 'state'] }) : fieldClear($Data.formData, { omitKeys: ['password'] });
146
144
 
147
- 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);
148
146
 
149
- MessagePlugin.success($Prop.actionType === 'upd' ? '编辑成功' : '添加成功');
147
+ MessagePlugin.success(result.msg);
150
148
  $Emit('success');
151
149
  $Method.onClose();
152
150
  } catch (error) {