Browse Source

🎟 框架升级

master
wangxiang 3 years ago
parent
commit
e660125c10
  1. 9
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/controller/UserController.java
  2. 2
      kicc-register/src/main/resources/bootstrap.yml
  3. 12
      kicc-ui/src/views/system/user/DeptTree.vue
  4. 63
      kicc-ui/src/views/system/user/UserDetail.vue
  5. 100
      kicc-ui/src/views/system/user/UserModal.vue
  6. 185
      kicc-ui/src/views/system/user/index.vue
  7. 170
      kicc-ui/src/views/system/user/user.data.ts

9
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/controller/UserController.java

@ -26,6 +26,7 @@ import com.cloud.kicc.common.security.util.SecurityUtils;
import com.pig4cloud.plugin.excel.annotation.ResponseExcel; import com.pig4cloud.plugin.excel.annotation.ResponseExcel;
import com.pig4cloud.plugin.excel.annotation.Sheet; import com.pig4cloud.plugin.excel.annotation.Sheet;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@ -45,8 +46,8 @@ import java.util.stream.Collectors;
* @Date: 2022/2/24 * @Date: 2022/2/24
*/ */
@RestController @RestController
@RequiredArgsConstructor
@RequestMapping(AppConstants.APP_SYSTEM + "/user") @RequestMapping(AppConstants.APP_SYSTEM + "/user")
@AllArgsConstructor
public class UserController { public class UserController {
private final UserService userService; private final UserService userService;
@ -134,10 +135,10 @@ public class UserController {
@GetMapping("/profile") @GetMapping("/profile")
public R profile() { public R profile() {
KiccUser entfrmUser = SecurityUtils.getUser(); KiccUser kiccUser = SecurityUtils.getUser();
if (entfrmUser != null) { if (kiccUser != null) {
ResultVo resultVo = new ResultVo(); ResultVo resultVo = new ResultVo();
User user = userService.getById(entfrmUser.getId() + ""); User user = userService.getById(kiccUser.getId() + "");
if (user != null) { if (user != null) {
String roleNames = SecurityUtils.getRoles().stream().map(roleId -> roleService.getById(roleId).getName()) String roleNames = SecurityUtils.getRoles().stream().map(roleId -> roleService.getById(roleId).getName())
.collect(Collectors.joining(",")); .collect(Collectors.joining(","));

2
kicc-register/src/main/resources/bootstrap.yml

@ -7,7 +7,7 @@ db:
user: ${MYSQL_USER:root} user: ${MYSQL_USER:root}
password: ${MYSQL_PWD:root} password: ${MYSQL_PWD:root}
url: url:
0: jdbc:mysql://${MYSQL_HOST:120.26.168.56}:${MYSQL_PORT:8052}/${MYSQL_DB:kicc_config}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true 0: jdbc:mysql://${MYSQL_HOST:127.0.0.1}:${MYSQL_PORT:3306}/${MYSQL_DB:kicc_config}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
nacos: nacos:
core: core:

12
kicc-ui/src/views/system/user/DeptTree.vue

@ -13,7 +13,8 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, onMounted, ref } from 'vue'; import { defineComponent, onMounted, ref } from 'vue';
import { BasicTree, TreeItem } from '/@/components/Tree'; import { BasicTree, TreeItem } from '/@/components/Tree';
import { departTreeList } from '/@/api/system/dept'; import { deptList } from '/@/api/system/dept';
import { listToTree } from "/@/utils/helper/treeHelper";
export default defineComponent({ export default defineComponent({
name: 'DeptTree', name: 'DeptTree',
@ -23,17 +24,16 @@
const treeData = ref<TreeItem[]>([]); const treeData = ref<TreeItem[]>([]);
async function fetch() { async function fetch() {
treeData.value = await departTreeList(); treeData.value = listToTree(await deptList());
} }
function handleSelect(keys: string, e) { function handleSelect(keys: string, e) {
emit('select', keys[0]); emit('select', keys[0]);
console.log(keys, e);
} }
onMounted(() => { onMounted(() => fetch());
fetch();
});
return { treeData, handleSelect }; return { treeData, handleSelect };
}, }
}); });
</script> </script>

63
kicc-ui/src/views/system/user/UserDetail.vue

@ -1,63 +0,0 @@
<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>
import { defineComponent, 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';
export default defineComponent({
name: 'AccountDetail',
components: { PageWrapper, ATabs: Tabs, ATabPane: Tabs.TabPane },
setup() {
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');
}
return { userId, currentKey, goBack };
},
});
</script>
<style></style>

100
kicc-ui/src/views/system/user/UserModal.vue

@ -1,73 +1,95 @@
<template> <template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit"> <BasicModal v-bind="$attrs"
<BasicForm @register="registerForm" /> width="720px"
@ok="handleSubmit"
@register="registerModal"
>
<BasicForm @register="registerForm"/>
</BasicModal> </BasicModal>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, computed, unref } from 'vue'; /**
* Copyright © 2020-2022 <a href="http://www.entfrm.com/">entfrm</a> All rights reserved.
* author entfrm开发团队-王翔
*/
import { defineComponent, ref, computed, unref, reactive } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal'; import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index'; import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
import { accountFormSchema } from './user.data'; import { userFormSchema } from './user.data';
import { departList } from '/@/api/system/dept'; import { deptList } from '/@/api/system/dept';
//import { set } from '/@/api/system/user'; import { addUser, editUser, getUser } from '/@/api/system/user';
import { listToTree } from "/@/utils/helper/treeHelper";
import { addMenu, editMenu, getMenu, getRoleMenuIds, listMenu } from "/@/api/system/menu";
import { ModalProps } from "/@/components/Modal";
export default defineComponent({ export default defineComponent({
name: 'UserModal', name: 'UserModal',
components: { BasicModal, BasicForm }, components: { BasicModal, BasicForm },
emits: ['success', 'register'], emits: ['success', 'register'],
setup(_, { emit }) { setup(props, { emit }) {
const isUpdate = ref(true); const tag = ref('');
const rowId = ref('');
const [registerForm, { setFieldsValue, updateSchema, resetFields, validate }] = useForm({ const [registerForm, {resetFields, setFieldsValue, updateSchema, validate, clearValidate}] = useForm({
labelWidth: 100, labelWidth: 100,
schemas: accountFormSchema, schemas: userFormSchema,
showActionButtonGroup: false, showActionButtonGroup: false,
actionColOptions: { actionColOptions: {
span: 23, span: 24
}, }
}); });
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields(); await resetFields();
setModalProps({ confirmLoading: false }); await clearValidate();
isUpdate.value = !!data?.isUpdate; tag.value = data._tag;
const userId = data.record?.id;
if (unref(isUpdate)) { const props: Partial<ModalProps> = { confirmLoading: false };
rowId.value = data.record.id; await updateSchema([
setFieldsValue({
...data.record,
});
}
const treeData = await departList();
updateSchema([
{ {
field: 'pwd', field: 'deptId',
show: !unref(isUpdate), componentProps: { treeData: listToTree(await deptList()) }
}, },
{ {
field: 'departId', field: 'password',
componentProps: { treeData }, show: tag.value == 'add'
}, }
]); ]);
switch (tag.value) {
case 'add':
props.title = '新增用户';
break;
case 'edit':
props.title = '编辑用户';
await setFieldsValue(await getUser(userId) || {});
break;
}
setModalProps(props);
}); });
const getTitle = computed(() => (!unref(isUpdate) ? '新增用户' : '编辑用户'));
async function handleSubmit() { async function handleSubmit() {
try { try {
const values = await validate(); const formData = await validate();
setModalProps({ confirmLoading: true }); setModalProps({ confirmLoading: true });
await set(values); switch (unref(tag)) {
case 'add':
await addMenu(formData);
break;
case 'edit':
await editMenu(formData);
break;
}
closeModal(); closeModal();
emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } }); emit('success');
} finally { } finally {
setModalProps({ confirmLoading: false }); setModalProps({ confirmLoading: false });
} }
} }
return { registerModal, registerForm, getTitle, handleSubmit }; return {
}, registerModal,
registerForm,
handleSubmit
};
}
}); });
</script> </script>

185
kicc-ui/src/views/system/user/index.vue

@ -1,155 +1,182 @@
<template> <template>
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex"> <PageWrapper dense
contentFullHeight
fixedHeight
contentClass="flex"
>
<DeptTree class="w-1/4 xl:w-1/5" @select="handleSelect"/> <DeptTree class="w-1/4 xl:w-1/5" @select="handleSelect"/>
<BasicTable @register="registerTable" class="w-3/4 xl:w-4/5" :searchInfo="searchInfo"> <BasicTable class="w-3/4 xl:w-4/5" @register="registerTable">
<template #toolbar> <template #toolbar>
<a-button type="primary" @click="handleCreate">新增用户</a-button> <a-button v-auth="['user_add']"
<a-button v-auth="['role_edit']" type="primary"
@click="handleAdd()"
>新增用户</a-button>
<a-button v-auth="['user_edit']"
type="primary" type="primary"
:disabled="state.single" :disabled="state.single"
@click="handleEdit()" @click="handleEdit()"
>修改用户</a-button> >修改用户</a-button>
<a-button v-auth="['role_del']" <a-button v-auth="['user_del']"
type="primary" type="primary"
:disabled="state.multiple" :disabled="state.multiple"
@click="handleDel()" @click="handleDel()"
>删除用户</a-button> >删除用户</a-button>
</template> </template>
<template #action="{ record }"> <template #action="{ record }">
<TableAction <TableAction :actions="[
:actions="[ {
{ icon: 'clarity:lock-line',
icon: 'clarity:lock-line', tooltip: '修改密码',
tooltip: '修改密码', onClick: handleUpdatePwd.bind(null, record),
onClick: handleSetPassword.bind(null, record), },
}, {
{ label: '编辑',
icon: 'clarity:note-edit-line', icon: 'fa6-regular:pen-to-square',
tooltip: '编辑用户资料', auth: ['role_edit'],
onClick: handleEdit.bind(null, record), onClick: handleEdit.bind(null, record)
}, },
{ {
icon: 'ant-design:delete-outlined', label: '删除',
color: 'error', icon: 'ant-design:delete-outlined',
tooltip: '删除此账号', auth: ['role_del'],
popConfirm: { color: 'error',
title: '是否确认删除', onClick: handleDel.bind(null, record)
confirm: handleDelete.bind(null, record), }]"
},
},
]"
/> />
</template> </template>
</BasicTable> </BasicTable>
<UserModal @register="registerModal" @success="handleSuccess" /> <UserModal @register="registerModal" @success="handleSuccess"/>
<PasswordModal @register="registerPasswordModal" @success="handlePasswordSuccess" /> <PasswordModal @register="registerPasswordModal" @success="handleUpdatePwd"/>
</PageWrapper> </PageWrapper>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive } from 'vue'; import { defineComponent, reactive, toRaw } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table'; import { BasicTable, useTable, TableAction } from '/@/components/Table';
//import { del, page } from '/@/api/system/user'; import { listUser, delUser, updatePwd } from '/@/api/system/user';
import { PageWrapper } from '/@/components/Page'; import { PageWrapper } from '/@/components/Page';
import DeptTree from './DeptTree.vue'; import DeptTree from './DeptTree.vue';
import { useModal } from '/@/components/Modal'; import { useModal } from '/@/components/Modal';
import UserModal from './UserModal.vue'; import UserModal from './UserModal.vue';
import PasswordModal from './PasswordModal.vue'; import PasswordModal from './PasswordModal.vue';
import { columns, searchFormSchema } from './user.data'; import { columns, searchFormSchema } from './user.data';
import { useGo } from '/@/hooks/web/usePage';
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
const { createMessage } = useMessage(); const { createMessage } = useMessage();
export default defineComponent({ export default defineComponent({
name: 'UserManagement', name: 'UserManagement',
components: { BasicTable, PageWrapper, DeptTree, UserModal, TableAction, PasswordModal }, components: {
BasicTable,
PageWrapper,
DeptTree,
TableAction,
UserModal,
PasswordModal
},
setup() { setup() {
const go = useGo(); const state = reactive({
//
ids: [],
//
single: true,
//
multiple: true,
//
searchInfo: {} as Recordable
});
const [registerModal, { openModal }] = useModal(); const [registerModal, { openModal }] = useModal();
const [registerPasswordModal, { openModal: openPasswordModal }] = useModal(); const [registerPasswordModal, { openModal: openPasswordModal }] = useModal();
const searchInfo = reactive<Recordable>({}); const [registerTable, { reload }] = useTable({
const [registerTable, { reload, updateTableDataRecord }] = useTable({
title: '用户列表', title: '用户列表',
api: page, api: listUser,
rowKey: 'id', rowKey: 'id',
columns, columns,
formConfig: { formConfig: {
labelWidth: 120, labelWidth: 120,
schemas: searchFormSchema, schemas: searchFormSchema,
autoSubmitOnEnter: true, autoSubmitOnEnter: true
}, },
rowSelection: { type: 'checkbox' },
useSearchForm: true, useSearchForm: true,
showTableSetting: true, showTableSetting: true,
bordered: true, bordered: true,
handleSearchInfoFn(info) { clickToRowSelect: false,
console.log('handleSearchInfoFn', info); searchInfo: state.searchInfo,
return info;
},
actionColumn: { actionColumn: {
width: 120, width: 120,
title: '操作', title: '操作',
dataIndex: 'action', dataIndex: 'action',
slots: { customRender: 'action' }, slots: { customRender: 'action' }
}, }
}); });
function handleCreate() { /** 处理多选框选中数据 */
openModal(true, { function handleSelectionChange(selection?: Recordable) {
isUpdate: false, const rawRows = toRaw(selection?.rows) || [];
}); state.ids = rawRows.map(item => item.id);
state.single = rawRows.length != 1;
state.multiple = !rawRows.length;
} }
function handleEdit(record: Recordable) { /** 新增按钮操作,行内新增与工具栏局域新增通用 */
openModal(true, { function handleAdd() {
record, openModal(true,{ _tag: 'add' });
isUpdate: true,
});
} }
async function handleDelete(record: Recordable) { /** 编辑按钮操作,行内编辑 */
await del({ ids: record.id }); function handleEdit(record?: Recordable) {
createMessage.success('删除成功!'); record = record || { id: toRaw(state.ids) };
handleSuccess(); openModal(true, { _tag: 'edit', record });
} }
function handleSuccess() { /** 处理修改用户密码 */
reload(); function handleUpdatePwd(record: Recordable) {
record = record || { id: toRaw(state.ids) };
openPasswordModal(true, { _tag: 'edit', record });
} }
function handleSelect(departId = '') { /** 删除按钮操作,行内删除 */
searchInfo.departId = departId; async function handleDel(record?: Recordable) {
reload(); const ids = record?.id || toRaw(state.ids);
} createConfirm({
iconType: 'warning',
function handleSetPassword(record: Recordable) { title: '警告',
openPasswordModal(true, { content: `是否确认删除用户编号为${ids}用户吗?`,
record, onOk: async () => {
isUpdate: true, await delUser(ids);
createMessage.success('删除成功!');
handleSuccess();
}
}); });
} }
function handleView(record: Recordable) { /** 处理表单提交成功 */
go('/system/account_detail/' + record.id); function handleSuccess() {
reload();
} }
function handlePasswordSuccess() { /** 处理部门管理点击 */
function handleSelect(departId = '') {
state.searchInfo.departId = departId;
reload(); reload();
} }
return { return {
state,
registerTable, registerTable,
registerModal, registerModal,
handleCreate, registerPasswordModal,
handleAdd,
handleEdit, handleEdit,
handleDelete, handleDel,
handleSelectionChange,
handleSuccess, handleSuccess,
handleSelect, handleSelect,
handleView, handleUpdatePwd
searchInfo,
handleSetPassword,
registerPasswordModal,
handlePasswordSuccess,
}; };
}, }
}); });
</script> </script>

170
kicc-ui/src/views/system/user/user.data.ts

@ -1,8 +1,8 @@
// import { roleAllList } from './../../../api/system/role';
import { BasicColumn } from '/@/components/Table'; import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table'; import { FormSchema } from '/@/components/Table';
import { h } from 'vue'; import { h } from 'vue';
import { Tag } from 'ant-design-vue'; import { Tag } from 'ant-design-vue';
import { listRole } from '/@/api/system/role';
export const columns: BasicColumn[] = [ export const columns: BasicColumn[] = [
{ {
@ -55,113 +55,155 @@ export const searchFormSchema: FormSchema[] = [
colProps: { span: 8 }, colProps: { span: 8 },
}, },
{ {
field: 'startDate', field: 'dateRange',
label: '起始时间', label: '创建时间',
component: 'DatePicker', component: 'RangePicker',
colProps: { span: 8 }, componentProps: {
}, style: { width:'100%' },
{ valueFormat: 'YYYY-MM-DD',
field: 'endDate', placeholder: ['开始日期','结束日期']
label: '截止时间', },
component: 'DatePicker', colProps: { span: 8 }
colProps: { span: 8 }, }
},
]; ];
export const accountFormSchema: FormSchema[] = [ export const userFormSchema: FormSchema[] = [
{ {
field: 'id', field: 'id',
label: 'ID', label: 'ID',
component: 'Input', component: 'Input',
show: false, show: false
}, },
{ {
field: 'account', field: 'nickName',
label: '用户', label: '用户昵称',
component: 'Input', component: 'Input',
helpMessage: ['本字段演示异步验证', '不能输入带有admin的用户名'],
},
{
field: 'pwd',
label: '密码',
component: 'InputPassword',
required: true,
ifShow: false,
},
{
field: 'sex',
label: '性别',
component: 'RadioButtonGroup',
defaultValue: 1,
componentProps: {
options: [
{ label: '男', value: 1 },
{ label: '女', value: 2 },
],
},
},
{
label: '授权角色',
field: 'roleId',
component: 'ApiSelect',
componentProps: {
// api: roleAllList,
resultField: 'list',
labelField: 'roleName',
valueField: 'id',
},
required: true, required: true,
colProps: {
span: 12
}
}, },
{ {
field: 'departId', field: 'deptId',
label: '所属部门', label: '归属机构',
component: 'TreeSelect', component: 'TreeSelect',
componentProps: { componentProps: {
replaceFields: { replaceFields: {
title: 'name', title: 'name',
key: 'id', key: 'id',
value: 'id', value: 'id'
}, },
getPopupContainer: () => document.body, getPopupContainer: () => document.body
}, },
required: true, required: true,
colProps: {
span: 12
}
}, },
{ {
field: 'realName', field: 'phone',
label: '姓名', label: '手机号',
component: 'Input', component: 'Input',
required: true, required: true,
rules: [
{
required: true,
message: '请输入手机号!',
},
{
pattern: new RegExp('^1[3|4|5|6|7|8|9][0-9]\\d{8}$'),
message: '请输入正确的手机号码!',
validateTrigger: 'blur'
}
]
}, },
{ {
field: 'name', field: 'email',
label: '昵称', label: '邮箱',
component: 'Input', component: 'Input',
required: true, required: true,
rules: [
{
required: true,
message: '请输入邮箱!',
},
{
type: 'email',
message: '请输入正确的邮箱地址!',
validateTrigger: ['blur', 'change']
}
]
}, },
{ {
label: '邮箱', field: 'userName',
field: 'email', label: '用户名',
component: 'Input', component: 'Input',
required: true, required: true,
colProps: {
span: 12
}
},
{
field: 'password',
label: '密码',
component: 'InputPassword',
required: true,
colProps: {
span: 12
}
},
{
field: 'sex',
label: '性别',
component: 'Select',
required: true,
componentProps: {
options: [
{ label: '男', value: '0' },
{ label: '女', value: '1' }
]
},
colProps: {
span: 12
}
}, },
{ {
field: 'status', field: 'status',
label: '状态', label: '状态',
component: 'RadioButtonGroup', component: 'RadioGroup',
defaultValue: '0', defaultValue: '0',
componentProps: { componentProps: {
options: [ options: [
{ label: '在职', value: '0' }, { label: '正常', value: '0' },
{ label: '离职', value: '1' }, { label: '停用', value: '1' }
], ]
}, },
colProps: {
span: 12
}
},
{
field: 'roleIds',
label: '授权角色',
component: 'ApiSelect',
componentProps: {
mode: 'multiple',
api: listRole,
labelField: 'name',
valueField: 'id'
},
colProps: {
span: 12
}
}, },
{ {
label: '备注', label: '备注',
field: 'remark', field: 'remarks',
component: 'InputTextArea', component: 'InputTextArea',
}, colProps: {
span: 24
}
}
]; ];
export const passwordFormSchema: FormSchema[] = [ export const passwordFormSchema: FormSchema[] = [

Loading…
Cancel
Save