-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
33 changed files
with
1,602 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { defHttp } from '/@/utils/http/axios'; | ||
|
||
enum Api { | ||
EmailConfig = '/tools/email/config', | ||
SendEmail = '/tools/email', | ||
} | ||
|
||
export const getEmailConfig = () => defHttp.get({ url: Api.EmailConfig }); | ||
|
||
export const saveEmailConfig = (params) => defHttp.post({ url: Api.EmailConfig, params }); | ||
|
||
export const sendEmail = (params) => | ||
defHttp.post({ url: Api.SendEmail, params }, { successMessageMode: 'message' }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { BasicPageParams, BasicPaginationResult } from '../model/baseModel'; | ||
import { defHttp } from '/@/utils/http/axios'; | ||
import qs from 'qs'; | ||
|
||
enum Api { | ||
Base = '/tools/storage', | ||
} | ||
|
||
export interface Storage { | ||
id: number; | ||
name: string; | ||
fileName: string; | ||
extName: string; | ||
path: string; | ||
type: string; | ||
size: string; | ||
username: string; | ||
} | ||
|
||
export type StorageListResult = BasicPaginationResult<Storage>; | ||
|
||
export const getStorageList = (params?: BasicPageParams) => | ||
defHttp.get<StorageListResult>({ | ||
url: Api.Base, | ||
params, | ||
paramsSerializer: (params) => qs.stringify(params, { arrayFormat: 'repeat' }), | ||
}); | ||
|
||
export const deleteStorage = (params: { ids: number[] }) => | ||
defHttp.post({ url: `${Api.Base}/delete`, params }, { successMessageMode: 'message' }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
apps/admin/src/views/demo/system/account/AccountDetail.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<template> | ||
<PageWrapper | ||
:title="`用户` + userId + `的资料`" | ||
content="这是用户资料详情页面。本页面仅用于演示相同路由在tab中打开多个页面并且显示不同的数据" | ||
contentBackground | ||
@back="goBack" | ||
> | ||
<template #extra> | ||
<a-button type="primary" danger> 禁用账号 </a-button> | ||
<a-button type="primary"> 修改密码 </a-button> | ||
</template> | ||
<template #footer> | ||
<a-tabs default-active-key="detail" v-model:activeKey="currentKey"> | ||
<a-tab-pane key="detail" tab="用户资料" /> | ||
<a-tab-pane key="logs" tab="操作日志" /> | ||
</a-tabs> | ||
</template> | ||
<div class="pt-4 m-4 desc-wrap"> | ||
<template v-if="currentKey == 'detail'"> | ||
<div v-for="i in 10" :key="i">这是用户{{ userId }}资料Tab</div> | ||
</template> | ||
<template v-if="currentKey == 'logs'"> | ||
<div v-for="i in 10" :key="i">这是用户{{ userId }}操作日志Tab</div> | ||
</template> | ||
</div> | ||
</PageWrapper> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { ref } from 'vue'; | ||
import { useRoute } from 'vue-router'; | ||
import { PageWrapper } from '/@/components/Page'; | ||
import { useGo } from '/@/hooks/web/usePage'; | ||
import { useTabs } from '/@/hooks/web/useTabs'; | ||
import { Tabs } from 'ant-design-vue'; | ||
defineOptions({ name: 'AccountDetail' }); | ||
const ATabs = Tabs; | ||
const ATabPane = Tabs.TabPane; | ||
const route = useRoute(); | ||
const go = useGo(); | ||
// 此处可以得到用户ID | ||
const userId = ref(route.params?.id); | ||
const currentKey = ref('detail'); | ||
const { setTitle } = useTabs(); | ||
// TODO | ||
// 本页代码仅作演示,实际应当通过userId从接口获得用户的相关资料 | ||
// 设置Tab的标题(不会影响页面标题) | ||
setTitle('详情:用户' + userId.value); | ||
// 页面左侧点击返回链接时的操作 | ||
function goBack() { | ||
// 本例的效果时点击返回始终跳转到账号列表页,实际应用时可返回上一页 | ||
go('/system/account'); | ||
} | ||
</script> | ||
|
||
<style></style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<template> | ||
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit"> | ||
<BasicForm @register="registerForm" /> | ||
</BasicModal> | ||
</template> | ||
<script lang="ts"> | ||
import { defineComponent, ref, computed, unref } from 'vue'; | ||
import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
import { BasicForm, useForm } from '/@/components/Form/index'; | ||
import { accountFormSchema } from './account.data'; | ||
import { getDeptList } from '/@/api/demo/system'; | ||
export default defineComponent({ | ||
name: 'AccountModal', | ||
components: { BasicModal, BasicForm }, | ||
emits: ['success', 'register'], | ||
setup(_, { emit }) { | ||
const isUpdate = ref(true); | ||
const rowId = ref(''); | ||
const [registerForm, { setFieldsValue, updateSchema, resetFields, validate }] = useForm({ | ||
labelWidth: 100, | ||
baseColProps: { span: 24 }, | ||
schemas: accountFormSchema, | ||
showActionButtonGroup: false, | ||
actionColOptions: { | ||
span: 23, | ||
}, | ||
}); | ||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { | ||
resetFields(); | ||
setModalProps({ confirmLoading: false }); | ||
isUpdate.value = !!data?.isUpdate; | ||
if (unref(isUpdate)) { | ||
rowId.value = data.record.id; | ||
setFieldsValue({ | ||
...data.record, | ||
}); | ||
} | ||
const treeData = await getDeptList(); | ||
updateSchema([ | ||
{ | ||
field: 'pwd', | ||
show: !unref(isUpdate), | ||
}, | ||
{ | ||
field: 'dept', | ||
componentProps: { treeData }, | ||
}, | ||
]); | ||
}); | ||
const getTitle = computed(() => (!unref(isUpdate) ? '新增账号' : '编辑账号')); | ||
async function handleSubmit() { | ||
try { | ||
const values = await validate(); | ||
setModalProps({ confirmLoading: true }); | ||
// TODO custom api | ||
console.log(values); | ||
closeModal(); | ||
emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } }); | ||
} finally { | ||
setModalProps({ confirmLoading: false }); | ||
} | ||
} | ||
return { registerModal, registerForm, getTitle, handleSubmit }; | ||
}, | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<template> | ||
<div class="m-4 mr-0 overflow-hidden bg-white"> | ||
<BasicTree | ||
title="部门列表" | ||
toolbar | ||
search | ||
treeWrapperClassName="h-[calc(100%-35px)] overflow-auto" | ||
:clickRowToExpand="false" | ||
:treeData="treeData" | ||
:fieldNames="{ key: 'id', title: 'deptName' }" | ||
@select="handleSelect" | ||
/> | ||
</div> | ||
</template> | ||
<script lang="ts"> | ||
import { defineComponent, onMounted, ref } from 'vue'; | ||
import { BasicTree, TreeItem } from '/@/components/Tree'; | ||
import { getDeptList } from '/@/api/demo/system'; | ||
export default defineComponent({ | ||
name: 'DeptTree', | ||
components: { BasicTree }, | ||
emits: ['select'], | ||
setup(_, { emit }) { | ||
const treeData = ref<TreeItem[]>([]); | ||
async function fetch() { | ||
treeData.value = (await getDeptList()) as unknown as TreeItem[]; | ||
} | ||
function handleSelect(keys) { | ||
emit('select', keys[0]); | ||
} | ||
onMounted(() => { | ||
fetch(); | ||
}); | ||
return { treeData, handleSelect }; | ||
}, | ||
}); | ||
</script> |
126 changes: 126 additions & 0 deletions
126
apps/admin/src/views/demo/system/account/account.data.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { getAllRoleList, isAccountExist } from '/@/api/demo/system'; | ||
import { BasicColumn, FormSchema } from '/@/components/Table'; | ||
|
||
export const columns: BasicColumn[] = [ | ||
{ | ||
title: '用户名', | ||
dataIndex: 'account', | ||
width: 120, | ||
}, | ||
{ | ||
title: '昵称', | ||
dataIndex: 'nickname', | ||
width: 120, | ||
}, | ||
{ | ||
title: '邮箱', | ||
dataIndex: 'email', | ||
width: 120, | ||
}, | ||
{ | ||
title: '创建时间', | ||
dataIndex: 'createTime', | ||
width: 180, | ||
}, | ||
{ | ||
title: '角色', | ||
dataIndex: 'role', | ||
width: 200, | ||
}, | ||
{ | ||
title: '备注', | ||
dataIndex: 'remark', | ||
}, | ||
]; | ||
|
||
export const searchFormSchema: FormSchema[] = [ | ||
{ | ||
field: 'account', | ||
label: '用户名', | ||
component: 'Input', | ||
colProps: { span: 8 }, | ||
}, | ||
{ | ||
field: 'nickname', | ||
label: '昵称', | ||
component: 'Input', | ||
colProps: { span: 8 }, | ||
}, | ||
]; | ||
|
||
export const accountFormSchema: FormSchema[] = [ | ||
{ | ||
field: 'account', | ||
label: '用户名', | ||
component: 'Input', | ||
helpMessage: ['本字段演示异步验证', '不能输入带有admin的用户名'], | ||
rules: [ | ||
{ | ||
required: true, | ||
message: '请输入用户名', | ||
}, | ||
{ | ||
validator(_, value) { | ||
return new Promise((resolve, reject) => { | ||
isAccountExist(value) | ||
.then(() => resolve()) | ||
.catch((err) => { | ||
reject(err.message || '验证失败'); | ||
}); | ||
}); | ||
}, | ||
}, | ||
], | ||
}, | ||
{ | ||
field: 'pwd', | ||
label: '密码', | ||
component: 'InputPassword', | ||
required: true, | ||
ifShow: false, | ||
}, | ||
{ | ||
label: '角色', | ||
field: 'role', | ||
component: 'ApiSelect', | ||
componentProps: { | ||
api: getAllRoleList, | ||
labelField: 'roleName', | ||
valueField: 'roleValue', | ||
}, | ||
required: true, | ||
}, | ||
{ | ||
field: 'dept', | ||
label: '所属部门', | ||
component: 'TreeSelect', | ||
componentProps: { | ||
fieldNames: { | ||
label: 'deptName', | ||
key: 'id', | ||
value: 'id', | ||
}, | ||
getPopupContainer: () => document.body, | ||
}, | ||
required: true, | ||
}, | ||
{ | ||
field: 'nickname', | ||
label: '昵称', | ||
component: 'Input', | ||
required: true, | ||
}, | ||
|
||
{ | ||
label: '邮箱', | ||
field: 'email', | ||
component: 'Input', | ||
required: true, | ||
}, | ||
|
||
{ | ||
label: '备注', | ||
field: 'remark', | ||
component: 'InputTextArea', | ||
}, | ||
]; |
Oops, something went wrong.