Browse Source

新增权限管理相关页面

master
许孟阳 1 year ago
parent
commit
4f20b48b37
  1. 6
      examples/App.vue
  2. 2
      packages/base/data/list-table.vue
  3. 27
      packages/base/data/modify-form.vue
  4. 2
      packages/base/data/table-action.vue
  5. 2
      packages/base/item/button.vue
  6. 2
      packages/base/item/select.vue
  7. 3
      packages/manage/common/head.vue
  8. 2
      packages/manage/common/menu-tree.vue
  9. 22
      packages/manage/router/index.vue
  10. 9
      packages/manage/views/buffer.vue
  11. 11
      packages/manage/views/index.ts
  12. 3
      packages/manage/views/login.vue
  13. 13
      packages/manage/views/permission.vue
  14. 145
      packages/manage/views/role.vue
  15. 134
      packages/manage/views/user.vue
  16. 2
      plugs/api/index.ts
  17. 36
      plugs/api/permission.ts
  18. 18
      plugs/api/public.ts
  19. 88
      plugs/api/role.ts
  20. 87
      plugs/api/user.ts
  21. 2
      plugs/element/message.ts
  22. 75
      plugs/element/rule.ts
  23. 8
      plugs/http/axios.ts
  24. 36
      plugs/i18n/en.ts
  25. 22
      plugs/i18n/zh.ts
  26. 19
      plugs/store/index.ts

6
examples/App.vue

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<template>
<Index :menus="menus" @updatePwd="pwd => console.log(pwd)" :checkUser="false" username="超级管理员" :closeAble="true">
<Index :menus="menus" @updatePwd="pwd => console.log(pwd)" :checkUser="true" username="超级管理员" :closeAble="true">
</Index>
</template>
@ -9,14 +9,14 @@ import { useStore } from "vuex"; @@ -9,14 +9,14 @@ import { useStore } from "vuex";
import { Index, Views } from "noob-mengyxu";
const store = useStore();
const { buff, dictionary, config, permission, role, status, log } = Views.menus;
const { buff, dictionary, config, permission, role, user, status, log } = Views.menus;
const menus = [
{
i18n: "menu.home", path: "home", icon: "HomeFilled"
},
{
i18n: "menu.operator", path: "operator", icon: "Platform", children: [
buff, dictionary, config, permission, role, status, log
buff, dictionary, config, permission, role, user, status, log
]
},
{

2
packages/base/data/list-table.vue

@ -90,7 +90,7 @@ const getValue = ( @@ -90,7 +90,7 @@ const getValue = (
value: any,
index?: number
) => {
if ((value == null || value == '') && value !== 0) {
if ((typeof value === 'undefined' || value === null || value === '') && value !== 0) {
return '--';
}
return value;

27
packages/base/data/modify-form.vue

@ -2,16 +2,19 @@ @@ -2,16 +2,19 @@
<div class="modify-form">
<el-form label-position="right" :class="class" :label-width="width ? width + 'px' : ''" :model="param"
ref="modifyForm" :rules="rules">
<el-form-item v-for="item in items" :label="item.name || t(item.i18n)" :prop="item.code">
<NoobSelect v-if="item.dict || item.maxValue" v-model="param[item.code]" :dict="item.dict"
:max-value="item.maxValue" full :placeholder="t('rule.pleaseSelect') + (item.name || t(item.i18n))"
:disabled="item.disabled" />
<NoobDate v-else-if="item.date" v-model="param[item.code]" :formater="item.formater" full
:placeholder="t('rule.pleaseSelect') + (item.name || t(item.i18n))" :disabled="item.disabled" />
<slot v-else-if="item.slot" :name="item.code" />
<NoobInput v-else v-model="param[item.code]" full :type="item.type" :rows="item.rows"
:placeholder="t('rule.pleaseEnter') + (item.name || t(item.i18n))" :disabled="item.disabled" />
</el-form-item>
<template v-for="item in items">
<el-form-item :label="item.name || t(item.i18n)" :prop="item.code"
v-if="!modify || (modify && !item.noModify)">
<NoobSelect v-if="item.dict || item.maxValue" v-model="param[item.code]" :dict="item.dict"
:max-value="item.maxValue" full :placeholder="t('rule.pleaseSelect') + (item.name || t(item.i18n))"
:disabled="item.disabled" />
<NoobDate v-else-if="item.date" v-model="param[item.code]" :formater="item.formater" full
:placeholder="t('rule.pleaseSelect') + (item.name || t(item.i18n))" :disabled="item.disabled" />
<slot v-else-if="item.slot" :name="item.code" />
<NoobInput v-else v-model="param[item.code]" full :type="item.type" :rows="item.rows"
:placeholder="t('rule.pleaseEnter') + (item.name || t(item.i18n))" :disabled="item.disabled" />
</el-form-item>
</template>
<slot></slot>
<el-form-item class="form-btns">
<NoobButton type="primary" @click="formConfirm">{{ t('base.confirm') }}</NoobButton>
@ -49,6 +52,10 @@ const prop = defineProps({ @@ -49,6 +52,10 @@ const prop = defineProps({
type: String,
default: null,
},
modify: {
type: Boolean,
default: false,
},
items: {
type: Array<any>(),
default: [],

2
packages/base/data/table-action.vue

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
<template>
<slot name="left"></slot>
<el-tooltip effect="dark" :content="t('base.modify')" placement="top">
<el-button v-if="modify" :size="state.size.size" type="primary" @click="emit('modify')" icon="EditPen" circle />
</el-tooltip>
@ -8,6 +9,7 @@ @@ -8,6 +9,7 @@
<el-tooltip effect="dark" :content="t('base.add')" placement="top">
<el-button v-if="add" :size="state.size.size" type="success" @click="emit('add')" icon="plus" circle />
</el-tooltip>
<slot></slot>
</template>
<script lang="ts" setup>

2
packages/base/item/button.vue

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
<template>
<el-button :class="type || state.style.name" :size="state.size.size" :type="type" :icon="icon" :disabled="disabled"
:plain="plain" :round="round" :circle="circle" :="loading" :text="text" :link="link">
:plain="plain" :round="round" :circle="circle" :loading="loading" :text="text" :link="link">
<slot />
</el-button>
</template>

2
packages/base/item/select.vue

@ -59,7 +59,7 @@ const prop = defineProps({ @@ -59,7 +59,7 @@ const prop = defineProps({
default: 'value'
},
});
const emit = defineEmits(["update:modelValue"]);
const emit = defineEmits(["update:modelValue", 'change']);
const myValue = ref<any>(null);
const width = ref('150px');
const setWidth = () => {

3
packages/manage/common/head.vue

@ -15,7 +15,8 @@ @@ -15,7 +15,8 @@
{{ t('head.center') }}
</el-dropdown-item>
<el-dropdown-item @click="updatePass">{{ t('pwd.changePwd') }}</el-dropdown-item>
<el-dropdown-item @click="emit('logout')">{{ t('head.logout') }}</el-dropdown-item>
<el-dropdown-item @click="dispatch('logout'); emit('logout')">{{ t('head.logout')
}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>

2
packages/manage/common/menu-tree.vue

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<template>
<el-menu :default-active="active" router class="menu-tree" :text-color="state.style.menuColor"
:background-color="state.style.menuBg" :active-text-color="state.style.menuActiveColor" :size="state.size.size">
<template v-for="menu in data">
<template v-for="menu in data || state.menus">
<template v-if="menu.children && menu.children.length > 0">
<el-sub-menu :index="menu.path" :key="menu.path">
<template #title>

22
packages/manage/router/index.vue

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<template>
<el-container :style="appMain" ref="main">
<el-container :style="appMain" ref="main" v-show="!flag.loading">
<el-header v-show="state.size.headHeight != '0px'" class="app-head" :height="state.size.headHeight">
<Head :title="title" @updatePwd="pwd => emit('updatePwd', pwd)" @logout="emit('logout')" :styleAble="styleAble"
@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
</template>
<script lang="ts" setup>
import { reactive, onMounted, ref } from "vue";
import { reactive, onMounted, ref, onBeforeUnmount } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { MenuTree, Head, Api } from "noob-mengyxu"
@ -33,8 +33,10 @@ const appMain = reactive({ @@ -33,8 +33,10 @@ const appMain = reactive({
const main = ref();
const flag = reactive({
showHeader: true,
showAside: true
showAside: true,
loading: false
})
let interval = 0;
const props = defineProps({
title: {
@ -89,8 +91,13 @@ const onResize = () => { @@ -89,8 +91,13 @@ const onResize = () => {
commit('initSize', height);
}
const getUser = () => {
const getUser = (first?) => {
if (!props.checkUser) {
return;
}
first && (flag.loading = true);
Api.pub.getInfo().then((rsp) => {
first && (flag.loading = false);
if (rsp) {
commit('updateState', ['user', rsp]);
} else {
@ -107,11 +114,16 @@ const onLogout = () => { @@ -107,11 +114,16 @@ const onLogout = () => {
onMounted(() => {
router.push("/")
props.checkUser && getUser();
getUser(true);
interval = setInterval(getUser, 5000);
window.onresize = onResize;
onResize();
});
onBeforeUnmount(() => {
clearInterval(interval);
})
</script>
<style lang='scss'>

9
packages/manage/views/buffer.vue

@ -17,10 +17,12 @@ @@ -17,10 +17,12 @@
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { onMounted, ref } from "vue";
import { Api, ListTable, SearchRow, NoobButton, TableAction, Element, Descriptions } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
const { prompt } = Element;
const { list, clean, set, del } = Api.buffer;
const result = ref([]);
@ -28,8 +30,8 @@ const result = ref([]); @@ -28,8 +30,8 @@ const result = ref([]);
const props = [
{ code: 'value', type: "expand", slot: true },
{ i18n: 'buffer.prop.1', code: 'key', width: 200 },
{ i18n: 'buffer.prop.2', code: 'effective', width: 100 },
{ i18n: 'buffer.prop.3', code: '失效时间', width: 180 },
{ i18n: 'buffer.prop.2', code: 'effective', width: 100, dict: 'boolean' },
{ i18n: 'buffer.prop.3', code: 'loseTime', width: 180 },
{ i18n: 'buffer.prop.4', code: 'action', width: 130, slot: true },
]
@ -45,12 +47,13 @@ const delate = (row) => { @@ -45,12 +47,13 @@ const delate = (row) => {
const delay = row => {
prompt(t(''), t(''), /^((\d{2}(([02468][048])|([13579][26]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\s((([0-1][0-9])|(2?[0-3]))\:([0-5]?[0-9])((\s)|(\:([0-5]?[0-9])))))?$/, '时间格式不正确').then(value => {
set({ key: row.key, loseTime: value }).then(query)
value && set({ key: row.key, loseTime: value }).then(query)
})
}
onMounted(() => {
query();
dispatch("getDictMap", ['boolean'])
});
</script>
<style lang="scss" scoped></style>

11
packages/manage/views/index.ts

@ -4,6 +4,7 @@ import Config from './config.vue'; @@ -4,6 +4,7 @@ import Config from './config.vue';
import Dictionary from './dictionary.vue';
import Permission from './permission.vue';
import Role from './role.vue';
import User from './user.vue';
import Status from './status.vue';
import Log from './log.vue';
const routes = [
@ -37,6 +38,11 @@ const routes = [ @@ -37,6 +38,11 @@ const routes = [
name: 'role',
component: Role,
},
{
path: '/user',
name: 'user',
component: User,
},
{
path: '/status',
name: 'status',
@ -62,7 +68,8 @@ const menus = { @@ -62,7 +68,8 @@ const menus = {
icon: 'Unlock',
},
role: { i18n: 'preMenu.operator.4', path: 'role', icon: 'User' },
status: { i18n: 'preMenu.operator.5', path: 'status', icon: 'Setting' },
log: { i18n: 'preMenu.operator.6', path: 'log', icon: 'Document' },
user: { i18n: 'preMenu.operator.5', path: 'user', icon: 'User' },
status: { i18n: 'preMenu.operator.6', path: 'status', icon: 'Setting' },
log: { i18n: 'preMenu.operator.7', path: 'log', icon: 'Document' },
};
export default { routes, menus };

3
packages/manage/views/login.vue

@ -12,7 +12,7 @@ import { useRouter } from "vue-router"; @@ -12,7 +12,7 @@ import { useRouter } from "vue-router";
import md5 from "js-md5";
import { Api, LoginForm } from "noob-mengyxu";
const { state, commit } = useStore();
const { state, commit, dispatch } = useStore();
const router = useRouter();
onBeforeMount(() => {
@ -29,6 +29,7 @@ const login = user => { @@ -29,6 +29,7 @@ const login = user => {
state.size.headHeight = state.size.head + 'px';
state.size.asideWidth = state.size.aside + 'px';
commit("initSize");
dispatch("getMenus");
router.push('/')
}
})

13
packages/manage/views/permission.vue

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<SearchRow :title="t('permission.title')" :del="false" @query="query" @add="addPermission">
<NoobInput v-model="example.code" :placeholder="t('permission.example.0')"></NoobInput>
</SearchRow>
<ListTable @query="query" :props="props" :example="example" :page="true" :data="result" rowKey="id"
<ListTable @query="query" :props="props" :example="example" :data="result" rowKey="id"
:treeProps="{ children: 'children' }">
<template #status="{ row }">
<div slot="reference" class="name-wrapper">
@ -38,13 +38,13 @@ @@ -38,13 +38,13 @@
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { Api, PageExample, PageResult, ListTable, SearchRow, NoobInput, TableAction, NoobTag, NoobSelect, ModifyForm, Element } from "noob-mengyxu";
import { Api, PageExample, ListTable, SearchRow, NoobInput, TableAction, NoobTag, NoobSelect, ModifyForm, Element } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { SimpleRequired } = Element;
const { state, dispatch } = useStore();
const { list, add, set, del } = Api.dictionary;
const result = ref(new PageResult());
const { list, add, set, del } = Api.permission;
const result = ref([]);
const example = reactive<any>(new PageExample());
const flag = reactive({
modify: false,
@ -67,7 +67,7 @@ const props = [ @@ -67,7 +67,7 @@ const props = [
{ i18n: 'permission.prop.4', code: 'perOrder', width: 80 },
{ i18n: 'permission.prop.5', code: 'status', dict: 'able_status', width: 80 },
{ i18n: 'permission.prop.6', code: 'perContent', width: 230 },
{ i18n: 'permission.prop.7', code: 'action', slot: true, type: 'action', width: 180, fixed: 'right' },
{ i18n: 'permission.prop.7', code: 'action', slot: true, width: 180, fixed: 'right' },
]
const items = [
@ -105,13 +105,14 @@ const addPermission = (row) => { @@ -105,13 +105,14 @@ const addPermission = (row) => {
const modify = (row) => {
permission.value = JSON.parse(JSON.stringify(row));
delete permission.value.children;
form.value?.clearValidate();
flag.modify = true;
flag.add = false;
}
const delate = (row) => {
Element.confirm(t('dict.delete.0'), t('dict.delete.1')).then(() => {
Element.confirm(t('permission.delete.0'), t('permission.delete.1')).then(() => {
del(row).then(query);
})
}

145
packages/manage/views/role.vue

@ -1,14 +1,157 @@ @@ -1,14 +1,157 @@
<template>
<SearchRow :title="t('role.title')" :del="false" :query="false" @query="query" @add="addRole"></SearchRow>
<ListTable @query="query" :props="props" :example="example" :data="result">
<template #action="{ row }">
<TableAction v-if="row.roleStatus == 'E'" @modify="modify(row)" @del="delate(row)">
<el-tooltip effect="dark" :content="t('role.setPer.0')" placement="right">
<el-button :size="state.size.size" type="success" @click="permission(row)" icon="Setting" circle />
</el-tooltip>
</TableAction>
</template>
</ListTable>
<el-dialog :title="t('base.add') + t('role.name')" v-model="flag.modify" :close-on-click-modal="false" top="15vh"
width="40%" @keydown.enter.native="confirm">
<ModifyForm ref="form" :param="role" :rules="rules" :items="items" @confirm="confirm" :width="100"
@cancel="flag.modify = false">
<template #roleCode>
<NoobInput v-model="role.roleCode" full :placeholder="t('rule.pleaseEnter') + t('role.prop.0')"
:disabled="!flag.add" />
</template>
</ModifyForm>
</el-dialog>
<el-dialog :title="t('role.setPer.0')" v-model="flag.per" :close-on-click-modal="false" top="15vh" width="40%"
@keydown.enter.native="setPermission">
<el-tree :size="state.size.size" ref="permissionTree" check-strictly :data="permissions" show-checkbox node-key="id"
:default-checked-keys="role.permissions" :props="{ children: 'children', label: 'name' }" render-after-expand
@check-change="checkChange" class="permissionTree" />
<div slot="footer" class="dialog-footer">
<NoobButton type="primary" @click="setPermission">{{ t('base.confirm') }}</NoobButton>
<NoobButton type="info" @click="flag.per = false">{{ t('base.cancel') }}</NoobButton>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { Api, ListTable, SearchRow, NoobInput, TableAction, NoobTag, NoobButton, ModifyForm, Element } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
const { list, add, set, del } = Api.role;
const { tree } = Api.permission;
const { SimpleRequired, SimpleCharacter } = Element;
const result = ref([]);
const example = reactive<any>({});
const flag = reactive({
modify: false,
add: false,
per: false
})
const form = ref();
const permissionTree = ref();
const role = ref<any>({});
const permissions = ref<any>([]);
const props = [
{ i18n: 'role.prop.0', code: 'roleCode', width: 120 },
{ i18n: 'role.prop.1', code: 'roleName', width: 120 },
{ i18n: 'role.prop.2', code: 'roleDesc', width: 180 },
{ i18n: 'role.prop.3', code: 'roleStatus', dict: 'role_status', width: 180 },
{ i18n: 'role.prop.4', code: 'action', slot: true, width: 180, fixed: 'right' }
]
const rules = {
roleCode: [new SimpleRequired('role.prop.0'), new SimpleCharacter(32, 4)],
roleName: [new SimpleRequired('role.prop.1'), new SimpleCharacter(15, 2)],
roleDesc: [new SimpleRequired('role.prop.2'), new SimpleCharacter(100)],
}
const items = [
{ i18n: 'role.prop.0', code: 'roleCode', slot: true },
{ i18n: 'role.prop.1', code: 'roleName' },
{ i18n: 'role.prop.2', code: 'roleDesc' }
]
const query = () => {
list(example).then((rsp: any) => result.value = rsp)
}
const addRole = () => {
role.value = {};
form.value?.clearValidate();
flag.add = true;
flag.modify = true;
}
const modify = row => {
role.value = JSON.parse(JSON.stringify(row))
form.value?.clearValidate();
flag.add = false;
flag.modify = true;
}
const delate = row => {
Element.confirm(t('role.delete.0'), t('role.delete.1')).then(() => {
del(row).then(() => {
commit('updateState', ['roleRefresh', true]);
query();
});
})
}
const confirm = () => {
const api = flag.add ? add : set;
api(role.value).then(rsp => {
if (rsp) {
query();
flag.modify = false;
commit('updateState', ['roleRefresh', true]);
}
})
}
const permission = (row) => {
role.value = JSON.parse(JSON.stringify(row))
role.value.flag = true;
permissionTree.value?.setCheckedNodes(role.value.permissions)
flag.per = true;
}
const setPermission = () => {
role.value.permissions = permissionTree.value?.getCheckedKeys();
set(role.value).then(rsp => {
if (rsp) {
query();
flag.per = false;
}
})
}
const checkChange = (data, checked) => {
const child = permissionTree.value?.getNode(data).childNodes
if (child != null && child.length > 0) {
for (let i = 0; i < child.length; i++) {
child[i].checked = checked
checkChange(data.children[i], checked)
}
}
}
onMounted(() => {});
onMounted(() => {
query();
tree().then(rsp => permissions.value = rsp);
dispatch("getDictMap", ["role_status"]);
});
</script>
<style lang="scss" scoped>
//@import url(); css
.permissionTree {
min-height: 500px;
}
</style>

134
packages/manage/views/user.vue

@ -0,0 +1,134 @@ @@ -0,0 +1,134 @@
<template>
<SearchRow :title="t('user.title')" :del="false" :query="false" @query="query" @add="addUser"></SearchRow>
<ListTable @query="query" :props="props" :example="example" :page="true" :data="result">
<template #action="{ row }">
<TableAction v-if="row.status == 'E'" @modify="modify(row)" @del="delate(row)">
<el-tooltip effect="dark" :content="t('user.reset.0')" placement="right">
<el-button :size="state.size.size" type="success" @click="resetPass(row)" icon="RefreshLeft" circle />
</el-tooltip>
</TableAction>
</template>
</ListTable>
<el-dialog :title="t('base.add') + t('user.name')" v-model="flag.modify" :close-on-click-modal="false" top="15vh"
width="40%" @keydown.enter.native="confirm">
<ModifyForm ref="form" :param="user" :rules="rules" :items="items" @confirm="confirm" :width="100"
@cancel="flag.modify = false" :modify="!flag.add">
<template #userId>
<NoobInput v-model="user.userId" full :placeholder="t('rule.pleaseEnter') + t('user.prop.0')"
:disabled="!flag.add" />
</template>
<template #password>
<NoobInput v-model="user.password" :placeholder="t('rule.pleaseEnter') + t('user.prop.1')" type="password"
full v-if="flag.add" />
</template>
<template #roles>
<el-select :size="state.size.size" class="form-item full" v-model="user.roles"
:placeholder="t('rule.pleaseSelect') + t('user.prop.2')" clearable multiple>
<el-option v-for="item in state.roles" :key="item.key" :value="item.key" :label="item.value" />
</el-select>
</template>
</ModifyForm>
</el-dialog>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { Api, ListTable, SearchRow, NoobInput, TableAction, NoobSelect, NoobButton, ModifyForm, Element, PageResult, PageExample } from "noob-mengyxu";
import md5 from "js-md5";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
const { list, add, set, del, reset } = Api.user;
const { SimpleRequired, Password, Username, Name, IdCard, Phone, Email } = Element;
const result = ref(new PageResult());
const example = reactive<any>(new PageExample());
const flag = reactive({
modify: false,
add: false
})
const form = ref();
const user = ref<any>({});
const props = [
{ i18n: 'user.prop.0', code: 'userId', width: 120 },
{ i18n: 'user.prop.3', code: 'name', width: 120 },
{ i18n: 'user.prop.4', code: 'phone', width: 180 },
{ i18n: 'user.prop.5', code: 'idCard', width: 180 },
{ i18n: 'user.prop.6', code: 'email', width: 180 },
{ i18n: 'user.prop.7', code: 'action', slot: true, width: 180, fixed: 'right' }
]
const rules = {
userId: [new Username()],
password: [new Password()],
roles: [new SimpleRequired('user.prop.2')],
name: [new SimpleRequired('user.prop.3'), new Name()],
idCard: [new IdCard()],
phone: [new Phone()],
email: [new Email()],
}
const items = [
{ i18n: 'user.prop.0', code: 'userId', slot: true },
{ i18n: 'user.prop.1', code: 'password', type: 'password', noModify: true },
{ i18n: 'user.prop.2', code: 'roles', slot: true },
{ i18n: 'user.prop.3', code: 'name' },
{ i18n: 'user.prop.4', code: 'phone' },
{ i18n: 'user.prop.5', code: 'idCard' },
{ i18n: 'user.prop.6', code: 'email' },
]
const query = () => {
list(example).then((rsp: any) => result.value = rsp)
}
const addUser = () => {
user.value = {};
form.value?.clearValidate();
flag.add = true;
flag.modify = true;
}
const modify = row => {
user.value = JSON.parse(JSON.stringify(row))
form.value?.clearValidate();
flag.add = false;
flag.modify = true;
}
const delate = row => {
Element.confirm(t('user.delete.0'), t('user.delete.1')).then(() => {
del(row).then(query);
})
}
const resetPass = row => {
Element.confirm(t('user.reset.1'), t('user.reset.2')).then(() => {
reset(row);
})
}
const confirm = () => {
const api = flag.add ? add : set;
user.value.password && (user.value.password = md5(user.value.password));
api(user.value).then(rsp => {
if (rsp) {
query();
flag.modify = false;
}
})
}
onMounted(() => {
query();
dispatch("getRoleMap");
});
</script>
<style lang="scss" scoped>
//@import url(); css
</style>

2
plugs/api/index.ts

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
export * as dictionary from './dictionary';
export * as log from './log';
export * as permission from './permission';
export * as role from './role';
export * as user from './user';
export * as buffer from './buffer';
export * as pub from './public';

36
plugs/api/permission.ts

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
import { get, post, put, delate } from '../http/axios';
import { PageResult } from '../constant';
const pageResult = new PageResult();
const root = 'permission';
const publik = 'public/permission';
export const list = (example) => {
return new Promise((resolve, reject) => {
@ -10,19 +9,19 @@ export const list = (example) => { @@ -10,19 +9,19 @@ export const list = (example) => {
if (rsp) {
resolve(rsp);
} else {
resolve(pageResult);
resolve([]);
}
},
(err) => {
resolve(pageResult);
resolve([]);
}
);
});
};
export const add = (dictionary) => {
export const add = (permission) => {
return new Promise((resolve, reject) => {
post(root, dictionary).then(
post(root, permission).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
@ -37,9 +36,9 @@ export const add = (dictionary) => { @@ -37,9 +36,9 @@ export const add = (dictionary) => {
});
};
export const set = (dictionary) => {
export const set = (permission) => {
return new Promise((resolve, reject) => {
put(root, dictionary).then(
put(root, permission).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
@ -54,9 +53,9 @@ export const set = (dictionary) => { @@ -54,9 +53,9 @@ export const set = (dictionary) => {
});
};
export const del = (dictionary) => {
export const del = (permission) => {
return new Promise((resolve, reject) => {
delate(root, dictionary).then(
delate(root + '/' + permission.id).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
@ -70,3 +69,20 @@ export const del = (dictionary) => { @@ -70,3 +69,20 @@ export const del = (dictionary) => {
);
});
};
export const tree = () => {
return new Promise((resolve, reject) => {
get(publik).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve([]);
}
},
(err) => {
resolve([]);
}
);
});
};

18
plugs/api/public.ts

@ -4,6 +4,7 @@ const urls = { @@ -4,6 +4,7 @@ const urls = {
info: 'public/info',
login: 'public/login',
logout: 'public/logout',
menu: 'public/menu',
};
export const getByCodes = (codes) => {
@ -65,3 +66,20 @@ export const logout = () => { @@ -65,3 +66,20 @@ export const logout = () => {
);
});
};
export const getMenus = () => {
return new Promise((resolve, reject) => {
get(urls.menu, null, true, true).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve([]);
}
},
(err) => {
resolve([]);
}
);
});
};

88
plugs/api/role.ts

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
import { get, post, put, delate } from '../http/axios';
const root = 'role';
const publik = 'public/roles';
export const list = (example) => {
return new Promise((resolve, reject) => {
get(root, example).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve([]);
}
},
(err) => {
resolve([]);
}
);
});
};
export const mapping = () => {
return new Promise((resolve, reject) => {
get(publik).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve([]);
}
},
(err) => {
resolve([]);
}
);
});
};
export const add = (role) => {
return new Promise((resolve, reject) => {
post(root, role).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const set = (role) => {
return new Promise((resolve, reject) => {
put(root, role).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const del = (role) => {
return new Promise((resolve, reject) => {
delate(root + '/' + role.roleCode).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};

87
plugs/api/user.ts

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
import { get, post, put, delate } from '../http/axios';
const root = 'user';
export const list = (example) => {
return new Promise((resolve, reject) => {
get(root, example).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve([]);
}
},
(err) => {
resolve([]);
}
);
});
};
export const add = (user) => {
return new Promise((resolve, reject) => {
post(root, user).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const set = (user) => {
return new Promise((resolve, reject) => {
put(root, user).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const del = (user) => {
return new Promise((resolve, reject) => {
delate(root + '/' + user.userId).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const reset = (user) => {
return new Promise((resolve, reject) => {
put(root + '/' + user.userId).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};

2
plugs/element/message.ts

@ -79,7 +79,7 @@ export const confirm = (msg: string, title: string) => { @@ -79,7 +79,7 @@ export const confirm = (msg: string, title: string) => {
resolve(true);
})
.catch((error) => {
resolve(false);
//do nothing
});
});
};

75
plugs/element/rule.ts

@ -9,9 +9,7 @@ export class SimpleRequired { @@ -9,9 +9,7 @@ export class SimpleRequired {
validator = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
const k = this.selection ? 'rule.pleaseSelect' : 'rule.pleaseEnter';
const msg = this.name
? t(k) + t(this.name).toLowerCase()
: t('rule.notNull');
const msg = this.name ? t(k) + t(this.name).toLowerCase() : t('rule.notNull');
callback(new Error(msg));
}
callback();
@ -96,10 +94,7 @@ export class Hexadecimal { @@ -96,10 +94,7 @@ export class Hexadecimal {
validator = (rule: any, value: any, callback: any) => {
if (value == null) {
callback();
} else if (
value.trim().length == 0 ||
!new RegExp(/^[0-9a-fA-F\s]+$/).test(value)
) {
} else if (value.trim().length == 0 || !new RegExp(/^[0-9a-fA-F\s]+$/).test(value)) {
callback(new Error(t('rule.hexadecimal')));
} else if (this.min != null && value.length < this.min) {
callback(new Error(t('rule.minLen', [this.min])));
@ -117,11 +112,7 @@ export class Hexadecimal { @@ -117,11 +112,7 @@ export class Hexadecimal {
export class Longitude extends Character {
constructor() {
super(
new RegExp(
/^-?((0|1?[0-7]?[0-9]?)(([.][0-9]{1,6})?)|180(([.][0]{1,6})?))$/
)
);
super(new RegExp(/^-?((0|1?[0-7]?[0-9]?)(([.][0-9]{1,6})?)|180(([.][0]{1,6})?))$/));
}
}
export class Latitude extends Character {
@ -132,20 +123,12 @@ export class Latitude extends Character { @@ -132,20 +123,12 @@ export class Latitude extends Character {
export class Email extends Character {
constructor() {
super(
new RegExp(
/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/
)
);
super(new RegExp(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/));
}
}
export class Phone extends Character {
constructor() {
super(
new RegExp(
/^(0|86|17951)?(13[0-9]|15[012356789]|17[0135678]|18[0-9]|14[57])[0-9]{8}$/
)
);
super(new RegExp(/^(0|86|17951)?(13[0-9]|15[012356789]|17[0135678]|18[0-9]|14[57])[0-9]{8}$/));
}
}
@ -215,17 +198,9 @@ export class IdCard { @@ -215,17 +198,9 @@ export class IdCard {
callback(new Error(t('rule.idCard.area')));
}
const sBirthday =
value.substr(6, 4) +
'-' +
Number(value.substr(10, 2)) +
'-' +
Number(value.substr(12, 2));
const sBirthday = value.substr(6, 4) + '-' + Number(value.substr(10, 2)) + '-' + Number(value.substr(12, 2));
const d = new Date(sBirthday.replace(/-/g, '/'));
if (
sBirthday !=
d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()
) {
if (sBirthday != d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()) {
callback(new Error(t('rule.idCard.birth')));
}
for (let i = 17; i >= 0; i--) {
@ -256,6 +231,27 @@ export class SimplePassword { @@ -256,6 +231,27 @@ export class SimplePassword {
};
}
export class Username {
required: boolean = true;
trigger = 'blur';
min?: Number = 4;
max?: Number = 16;
validator = (rule: any, value: any, callback: any) => {
if (value != null && value.length != 0) {
if (!new RegExp('^[a-zA-Z0-9]{4,16}$').test(value)) {
callback(new Error(t('rule.username.0')));
}
if (/(^\_)|(\__)|(\_+$)/.test(value)) {
callback(new Error(t('rule.username.1')));
}
if (!new RegExp('^[^ ]+$').test(value)) {
callback(new Error(t('rule.username.2')));
}
}
callback();
};
}
export class Password {
required: boolean = true;
trigger = 'blur';
@ -266,9 +262,7 @@ export class Password { @@ -266,9 +262,7 @@ export class Password {
callback(new Error(t('rule.pleaseEnter') + t('pwd.pwd').toLowerCase()));
} else if (value.length < 8 || value.length > 20) {
callback(new Error(t('pwd.length', [8, 20])));
} else if (
!new RegExp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).*$').test(value)
) {
} else if (!new RegExp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).*$').test(value)) {
callback(new Error(t('pwd.required')));
} else if (!new RegExp('^[^ ]+$').test(value)) {
callback(new Error(t('pwd.noSpace')));
@ -276,3 +270,14 @@ export class Password { @@ -276,3 +270,14 @@ export class Password {
callback();
};
}
export class Name {
pattern: RegExp = new RegExp('^[a-zA-Z\u4e00-\u9fa5]{1,10}$');
trigger = 'blur';
validator = (rule: any, value: any, callback: any) => {
if (value != null && value.length != 0 && !this.pattern.test(value)) {
callback(new Error(t('rule.name')));
}
callback();
};
}

8
plugs/http/axios.ts

@ -1,9 +1,12 @@ @@ -1,9 +1,12 @@
/* eslint-disable */
import axios from 'axios';
import { loading, close, showMessage } from '../element';
import { useRouter } from 'vue-router';
import { i18n } from '../i18n';
const t = i18n.t;
const router = useRouter();
const config = {
baseURL: process.env.VUE_APP_BASE_URL ? '/api' : '',
timeout: 60 * 1000,
@ -13,8 +16,7 @@ const config = { @@ -13,8 +16,7 @@ const config = {
const _axios = axios.create(config);
_axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
_axios.defaults.headers.put['Content-Type'] = 'application/json;charset=UTF-8';
_axios.defaults.headers.delete['Content-Type'] =
'application/json;charset=UTF-8';
_axios.defaults.headers.delete['Content-Type'] = 'application/json;charset=UTF-8';
let logout;
@ -159,7 +161,7 @@ function handResponse(response, resolve, noMsg, noLoading) { @@ -159,7 +161,7 @@ function handResponse(response, resolve, noMsg, noLoading) {
}
} else {
if (response.message == 'session timeout') {
logout();
router.push('/login');
}
if (response.message == 'no permission') {
response.message = t('http.unPermission');

36
plugs/i18n/en.ts

@ -18,7 +18,7 @@ export default class English { @@ -18,7 +18,7 @@ export default class English {
key: 'Key',
value: 'Value',
import: 'Import',
export: 'Export'
export: 'Export',
};
pwd = {
@ -75,6 +75,12 @@ export default class English { @@ -75,6 +75,12 @@ export default class English {
birth: 'The date of birth on the ID card is illegal',
error: 'The ID number is illegal',
},
username: [
'The username consists of letters, numbers, and is between 4-16 in length',
"Usernames cannot be underscored '_'",
'Usernames cannot contain spaces',
],
name: 'The name consists of Chinese characters or letters and is no more than 10 in length',
};
http = {
@ -112,12 +118,28 @@ export default class English { @@ -112,12 +118,28 @@ export default class English {
delete: ['Are you sure you want to remove the permission?', 'Tips'],
};
role = {
title: 'Role manage',
name: 'role',
prop: ['Code', 'Name', 'Remark', 'Status', 'Action'],
setPer: ['Assign permissions'],
delete: ['Are you sure you want to remove the role?', 'Tips'],
};
user = {
title: 'User manage',
name: 'user',
prop: ['Username', 'Password', 'Role', 'Name', 'Phone', 'IdCard', 'Email', 'Action'],
delete: ['Are you sure you want to remove the user?', 'Tips'],
reset: ['Reset password', 'Are you sure you want to reset the password of this user to the default password "abcd1234"?', 'Tips'],
};
buffer = {
title: '缓存管理',
clean: '清空失效缓存',
modify: '修改有效期',
prop: ['缓存值', '唯一键', '是否有效', '失效时间', '操作'],
delete: ['确定要删除此条缓存吗?', '提示'],
delay: ['请输入失效时间(yyyy-MM-dd HH:mm:ss)', '修改'],
title: 'Cache manage',
clean: 'Clear the invalid cache',
modify: 'Modify the expiration date',
prop: ['Value', 'Key', 'Effective', 'Expiration time', 'Action'],
delete: ['Are you sure you want to delete this cache?', 'Tips'],
delay: ['Please enter an expiration time(yyyy-MM-dd HH:mm:ss)', 'Modify'],
};
}

22
plugs/i18n/zh.ts

@ -18,7 +18,7 @@ export default class Zh { @@ -18,7 +18,7 @@ export default class Zh {
key: '键',
value: '值',
import: '导入',
export: '导出'
export: '导出',
};
pwd = {
@ -75,6 +75,8 @@ export default class Zh { @@ -75,6 +75,8 @@ export default class Zh {
birth: '你输入的身份证出生日期非法',
error: '你输入的身份证号非法',
},
username: ['用户名由字母,数字组成,长度4-16之间', "用户名首尾不能出现下划线'_'", '用户名不能包含空格'],
name: '姓名由汉字或字母组成,且长度不超过10',
};
http = {
@ -85,7 +87,7 @@ export default class Zh { @@ -85,7 +87,7 @@ export default class Zh {
};
preMenu = {
operator: ['缓存管理', '系统配置', '数据字典', '权限管理', '角色管理', '状态管理', '接口日志'],
operator: ['缓存管理', '系统配置', '数据字典', '权限管理', '角色管理', '用户管理', '状态管理', '接口日志'],
};
log = {
@ -112,6 +114,22 @@ export default class Zh { @@ -112,6 +114,22 @@ export default class Zh {
delete: ['确定要删除该权限吗?', '提示'],
};
role = {
title: '角色管理',
name: '角色',
prop: ['角色编码', '角色名称', '备注', '角色状态', '操作'],
setPer: ['分配权限'],
delete: ['确定要删除该角色吗?', '提示'],
};
user = {
title: '用户管理',
name: '用户',
prop: ['用户名', '密码', '用户角色', '姓名', '手机号码', '身份证号', '邮箱', '操作'],
delete: ['确定要删除该用户吗?', '提示'],
reset: ['重置密码', '确定要将该用户密码重置为默认密码"Abcd1234"吗?', '提示'],
};
buffer = {
title: '缓存管理',
clean: '清空失效缓存',

19
plugs/store/index.ts

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import { createStore as create } from 'vuex';
import { Styles, Size } from '../config';
import { getByCodes, getInfo } from '../api/public';
import { getByCodes, getMenus, logout } from '../api/public';
import { mapping } from '../api/role';
export class State {
dict = {
@ -9,6 +10,9 @@ export class State { @@ -9,6 +10,9 @@ export class State {
B: '禁用',
},
};
roles = {};
menus = [];
roleRefresh = true;
style = Styles.plain;
size = Size.normal;
}
@ -41,6 +45,19 @@ export class Actions { @@ -41,6 +45,19 @@ export class Actions {
}
});
};
getRoleMap = ({ state, commit }) => {
state.roleRefresh &&
mapping().then((rsp) => {
commit('updateState', ['roles', rsp]);
commit('updateState', ['roleRefresh', false]);
});
};
getMenus = ({ state, commit }) => {
getMenus().then((rsp) => commit('updateState', ['menus', rsp]));
};
logout = ({ state, commit }) => {
logout().then((rsp) => window.location.reload());
};
}
export class Mutations {

Loading…
Cancel
Save