Browse Source

fix bug v0.2.4

master
许孟阳 2 years ago
parent
commit
71bf8a3125
  1. 3
      .env.development
  2. 2
      .env.production
  3. 1
      dist/css/chunk-vendors.6e16aa55.css
  4. 1
      dist/css/index.3ad5135e.css
  5. 1
      dist/index.html
  6. 36
      dist/js/chunk-vendors.2810f37d.js
  7. 1
      dist/js/chunk-vendors.2810f37d.js.map
  8. 2
      dist/js/index.29912fb5.js
  9. 1
      dist/js/index.29912fb5.js.map
  10. 39
      examples/App.vue
  11. 44
      examples/config/language/en.ts
  12. 7
      examples/config/language/index.ts
  13. 37
      examples/config/language/zh.ts
  14. 5
      examples/config/router.ts
  15. 5
      examples/main.ts
  16. 4
      examples/store/actions.ts
  17. 6
      examples/store/index.ts
  18. 1
      examples/store/mutations.js
  19. 3
      examples/store/mutations.ts
  20. 17
      examples/store/state.ts
  21. 82
      examples/view/base/form.vue
  22. 43
      examples/view/base/table.vue
  23. 13
      examples/view/home.vue
  24. 2
      examples/view/tool/color.vue
  25. 2
      examples/view/tool/terminal.vue
  26. 26
      package.json
  27. 58
      packages/base/data/descriptions.vue
  28. 81
      packages/base/data/infomation.vue
  29. 144
      packages/base/data/list-table.vue
  30. 68
      packages/base/data/login-form.vue
  31. 26
      packages/base/data/modify-form.vue
  32. 24
      packages/base/data/search-row.vue
  33. 40
      packages/base/data/table-action.vue
  34. 32
      packages/base/index.ts
  35. 64
      packages/base/item/button.vue
  36. 69
      packages/base/item/datetime.vue
  37. 68
      packages/base/item/input.vue
  38. 62
      packages/base/item/select.vue
  39. 24
      packages/base/item/tag.vue
  40. 116
      packages/base/table/list-table.vue
  41. 51
      packages/base/table/search-input.vue
  42. 116
      packages/manage/common/head.vue
  43. 34
      packages/manage/common/menu-tree.vue
  44. 7
      packages/manage/index.ts
  45. 97
      packages/manage/router/index.vue
  46. 56
      packages/manage/views/buffer.vue
  47. 14
      packages/manage/views/config.vue
  48. 115
      packages/manage/views/dictionary.vue
  49. 68
      packages/manage/views/index.ts
  50. 43
      packages/manage/views/log.vue
  51. 56
      packages/manage/views/login.vue
  52. 136
      packages/manage/views/permission.vue
  53. 14
      packages/manage/views/role.vue
  54. 14
      packages/manage/views/status.vue
  55. 22
      packages/tool/color.vue
  56. 8
      packages/tool/terminal-split.vue
  57. 5
      packages/tool/terminal.vue
  58. 66
      plugs/api/buffer.ts
  59. 72
      plugs/api/dictionary.ts
  60. 5
      plugs/api/index.ts
  61. 20
      plugs/api/log.ts
  62. 72
      plugs/api/permission.ts
  63. 67
      plugs/api/public.ts
  64. 5
      plugs/config/index.ts
  65. 32
      plugs/config/language/chinese.ts
  66. 31
      plugs/config/language/english.ts
  67. 8
      plugs/config/language/index.ts
  68. 7
      plugs/config/size/index.ts
  69. 23
      plugs/config/size/large.ts
  70. 29
      plugs/config/size/normal.ts
  71. 25
      plugs/config/size/small.ts
  72. 6
      plugs/config/styles/dark.ts
  73. 9
      plugs/config/styles/index.ts
  74. 11
      plugs/config/styles/light.ts
  75. 11
      plugs/config/styles/plain.ts
  76. 8
      plugs/constant.ts
  77. 29
      plugs/element/formatter.ts
  78. 31
      plugs/element/message.ts
  79. 142
      plugs/element/rule.ts
  80. 20
      plugs/http/axios.ts
  81. 226
      plugs/http/axios2.ts
  82. 2
      plugs/http/index.ts
  83. 150
      plugs/i18n/en.ts
  84. 17
      plugs/i18n/index.ts
  85. 147
      plugs/i18n/zh.ts
  86. 9
      plugs/index.ts
  87. 94
      plugs/store/index.ts
  88. 7
      tsconfig.json
  89. 19
      vue.config.js
  90. 30
      yarn.lock

3
.env.development

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
NODE_ENV="preview"
# VUE_APP_BASE_URL="http://172.16.16.120:8080"
VUE_APP_BASE_URL="http://localhost"

2
.env.production

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
NODE_ENV="production"
VUE_APP_BASE_URL=""

1
dist/css/chunk-vendors.6e16aa55.css vendored

File diff suppressed because one or more lines are too long

1
dist/css/index.3ad5135e.css vendored

File diff suppressed because one or more lines are too long

1
dist/index.html vendored

@ -1 +0,0 @@ @@ -1 +0,0 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title></title><script defer="defer" src="/js/chunk-vendors.2810f37d.js"></script><script defer="defer" src="/js/index.29912fb5.js"></script><link href="/css/chunk-vendors.6e16aa55.css" rel="stylesheet"><link href="/css/index.3ad5135e.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but noob-mengyxu doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

36
dist/js/chunk-vendors.2810f37d.js vendored

File diff suppressed because one or more lines are too long

1
dist/js/chunk-vendors.2810f37d.js.map vendored

File diff suppressed because one or more lines are too long

2
dist/js/index.29912fb5.js vendored

File diff suppressed because one or more lines are too long

1
dist/js/index.29912fb5.js.map vendored

File diff suppressed because one or more lines are too long

39
examples/App.vue

@ -5,24 +5,29 @@ @@ -5,24 +5,29 @@
<script lang="ts" setup>
import { reactive, onMounted, ref } from "vue";
import { useStore } from "vuex";
import { Index } from "noob";
import { Index, Views } from "noob-mengyxu";
const store = useStore();
const { buff, dictionary, config, permission, role, status, log } = Views.menus;
const menus = [
{
title: "主页", path: "home", icon: ""
i18n: "menu.home", path: "home", icon: "HomeFilled"
},
{
i18n: "menu.operator", path: "operator", icon: "Platform", children: [
buff, dictionary, config, permission, role, status, log
]
},
{
title: "通用", path: "base", icon: "", children: [
{ title: "表格", path: "table", icon: "" },
{ title: "表单", path: "form", icon: "" },
i18n: "menu.base", path: "base", icon: "House", children: [
{ i18n: "menu.table", path: "table", icon: "List" },
{ i18n: "menu.form", path: "form", icon: "Postcard" },
]
},
{
title: "工具", path: "tool", icon: "", children: [
{ title: "终端", path: "terminal", icon: "" },
{ title: "颜色", path: "color", icon: "" },
i18n: "menu.tool", path: "tool", icon: "Tools", children: [
{ i18n: "menu.terminal", path: "terminal", icon: "Platform" },
{ i18n: "menu.color", path: "color", icon: "MagicStick" },
]
}
]
@ -32,17 +37,7 @@ onMounted(() => { }); @@ -32,17 +37,7 @@ onMounted(() => { });
</script>
<style lang="scss">
body {
font-size: 14px;
font-family: "Microsoft YaHei";
width: 100%;
height: 100%;
overflow: hidden;
padding: 0px;
margin: 0px;
}
::v-deep .no-padding .el-dialog__body {
background-color: black;
}
// ::v-deep .no-padding .el-dialog__body {
// background-color: black;
// }
</style>

44
examples/config/language/en.ts

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
import { Lang } from 'noob-mengyxu';
export default class En extends Lang.En {
table = {
title: 'Table demo',
props: [
'Case name',
'Task name',
'User name',
'Log content',
'Create time',
],
};
form = {
title: 'Form Example',
input: 'Input',
select: 'Select',
datePicker: 'Date picker',
pass: 'The verification passed',
bishu: 'Must enter',
bixuan: 'Must select',
maxLen: 'Max length',
char: 'Character',
num: 'Integer',
hex: 'Hexadecimal',
lan: 'Longitude',
lat: 'Latitude',
email: 'Email',
phone: 'Phone number',
idCard: 'ID card',
pwd: 'Simple password',
password: 'Password',
};
menu = {
operator: 'Operator',
home: 'Home',
base: 'General',
table: 'Table',
form: 'Form',
tool: 'Tool',
terminal: 'Terminal',
color: 'Color',
};
}

7
examples/config/language/index.ts

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
import Zh from './zh';
import En from './en';
import { Lang } from 'noob-mengyxu';
Lang.registerLang('zh', new Zh());
Lang.registerLang('en', new En());
export default Lang.i18n;

37
examples/config/language/zh.ts

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
import { Lang } from 'noob-mengyxu';
export default class Zh extends Lang.Zh {
table = {
title: '表格演示',
props: ['案件名称', '任务名称', '用户名', '日志内容', '产生时间'],
};
form = {
title: '表单演示',
input: '输入框',
select: '选择框',
datePicker: '时间选择框',
pass: '校验通过',
bishu: '必输',
bixuan: '必选',
maxLen: '最长',
char: '字符',
num: '整数',
hex: '十六进制数字',
lan: '经度',
lat: '纬度',
email: '电子邮箱',
phone: '手机号码',
idCard: '身份证号码',
pwd: '简单密码',
password: '普通密码',
};
menu = {
operator: '运维',
home: '主页',
base: '通用',
table: '表格',
form: '表单',
tool: '工具',
terminal: '终端',
color: '颜色',
};
}

5
examples/router/index.ts → examples/config/router.ts

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
import { Views } from 'noob-mengyxu';
import Home from '../view/home.vue';
import Table from '../view/base/table.vue';
import Form from '../view/base/form.vue';
@ -37,6 +38,10 @@ const routes: Array<RouteRecordRaw> = [ @@ -37,6 +38,10 @@ const routes: Array<RouteRecordRaw> = [
},
];
Views.routes.forEach((item) => {
routes.push(item);
});
const router = createRouter({
history: createWebHashHistory(),
routes,

5
examples/main.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import router from './config/router';
import store from './store';
import ElementPlus from 'element-plus';
@ -13,4 +13,7 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) { @@ -13,4 +13,7 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
app.use(ElementPlus, { size: 'default', locale: zhCn });
import i18n from './config/language';
app.use(i18n);
app.use(store).use(router).mount('#app');

4
examples/store/actions.ts

@ -1 +1,3 @@ @@ -1 +1,3 @@
export default {};
import { Store } from 'noob-mengyxu';
class Actions extends Store.Actions {}
export default new Actions();

6
examples/store/index.ts

@ -1,12 +1,10 @@ @@ -1,12 +1,10 @@
import { createStore } from 'plugs';
import { Store } from 'noob-mengyxu';
import state from './state';
import mutations from './mutations';
import actions from './actions';
export default createStore({
export default Store.createStore({
state,
getters: {},
mutations,
actions,
modules: {},
});

1
examples/store/mutations.js

@ -1 +0,0 @@ @@ -1 +0,0 @@
export default {};

3
examples/store/mutations.ts

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
import { Store } from 'noob-mengyxu';
class Mutations extends Store.Mutations {}
export default new Mutations();

17
examples/store/state.ts

@ -1,14 +1,9 @@ @@ -1,14 +1,9 @@
export default {
dict: {
test: {
a: 'A',
b: 'B',
c: 'C',
},
},
test: [
import { Store } from 'noob-mengyxu';
class State extends Store.State {
test = [
{ key: 'a', value: 'A' },
{ key: 'b', value: 'B' },
{ key: 'c', value: 'C' },
],
};
];
}
export default new State();

82
examples/view/base/form.vue

@ -1,15 +1,89 @@ @@ -1,15 +1,89 @@
<template>
<span>待开发</span>
<h2>{{ t('form.title') }}</h2>
<el-row>
<el-col :span="8">
<ModifyForm class="modify-form-demo" @cancel="demo = {}" @confirm="" :rules="rules" :param="demo" :width="140"
:items="demoItems">
</ModifyForm>
</el-col>
<el-col :span="8">
<ModifyForm ref="form" class="modify-form-demo" @cancel="cancel" @confirm="confirm" :rules="rules"
:param="param" :width="140" :items="items">
</ModifyForm>
</el-col>
<el-col :span="8">
<LoginForm @login="e => console.log(e)"></LoginForm>
</el-col>
</el-row>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { onMounted, ref } from "vue";
import { ModifyForm, Element, LoginForm } from 'noob-mengyxu';
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { showMessage, SimpleRequired, SimpleCharacter, Character, SimpleNumber, Hexadecimal, Longitude, Latitude, Email, Phone, Ipv4, Ipv6, IdCard, SimplePassword, Password } = Element;
const rules = {
bishu: [new SimpleRequired('form.bishu')],
bixuan: [new SimpleRequired('form.bixuan', true)],
maxLen: [new SimpleCharacter(10)],
char: [new Character(new RegExp(/^[^ ]+$/))],
num: [new SimpleNumber(10, 20)],
hex: [new Hexadecimal(2, 8)],
lan: [new Longitude()],
lat: [new Latitude()],
email: [new Email()],
phone: [new Phone()],
ipv4: [new Ipv4()],
ipv6: [new Ipv6()],
idCard: [new IdCard()],
pwd: [new SimplePassword()],
password: [new Password()]
}
const demo = ref<any>({});
const demoItems = [
{ i18n: 'form.input', code: 'input' },
{ i18n: 'form.select', code: 'select', dict: 'test' },
{ i18n: 'form.NoobDate', code: 'date', date: true },
]
const items = [
{ i18n: 'form.bishu', code: 'bishu' },
{ i18n: 'form.bixuan', code: 'bixuan', dict: 'test' },
{ i18n: 'form.maxLen', code: 'maxLen' },
{ i18n: 'form.char', code: 'char' },
{ i18n: 'form.num', code: 'num' },
{ i18n: 'form.hex', code: 'hex' },
{ i18n: 'form.lan', code: 'lan' },
{ i18n: 'form.lat', code: 'lat' },
{ i18n: 'form.email', code: 'email' },
{ i18n: 'form.phone', code: 'phone' },
{ name: 'ipv4', code: 'ipv4' },
{ name: 'ipv6', code: 'ipv6' },
{ i18n: 'form.idCard', code: 'idCard' },
{ i18n: 'form.pwd', code: 'pwd' },
{ i18n: 'form.password', code: 'password' },
]
const param = ref<any>({});
const form = ref();
const { state, commit, dispatch } = useStore();
const cancel = () => {
param.value = {};
setTimeout(() => {
form.value?.clearValidate();
}, 50);
}
const confirm = () => {
showMessage('success', t('form.pass'));
}
onMounted(() => { });
</script>
<style lang="scss" scoped>
//@import url(); css
::v-deep .modify-form-demo {
width: 400px;
float: left;
padding: 20px;
}
</style>

43
examples/view/base/table.vue

@ -1,54 +1,67 @@ @@ -1,54 +1,67 @@
<template>
<SearchRow title="表格演示">
<SearchRow :title="t('table.title')">
<template #default>
<SearchInput v-model="example.aaa" :width="180"></SearchInput>
<DictSelect v-model="example.bbb" dict="test"></DictSelect>
<DictSelect v-model="example.ccc" stateProp="test" :width="120"></DictSelect>
<NoobInput v-model="example.aaa" :width="180"></NoobInput>
<NoobSelect v-model="example.bbb" dict="test"></NoobSelect>
<NoobSelect v-model="example.ccc" stateProp="test" :width="120"></NoobSelect>
</template>
</SearchRow>
<ListTable :data="data" :height="800" :props="prop"></ListTable>
<ListTable :data="data" :props="prop" :page="true"></ListTable>
<br />
<br />
<Infomation :num="100" title="总数" icon="DataAnalysis"></Infomation>
<Infomation :num="100" title="总数" icon="DataAnalysis" :center="true"></Infomation>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { ListTable, SearchRow, SearchInput, DictSelect } from "noob";
import { ListTable, SearchRow, NoobInput, NoobSelect, Infomation } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { state, commit, dispatch } = useStore();
const { state } = useStore();
const { t } = useI18n();
const example = reactive({
page: 1,
size: 10,
aaa: "",
bbb: 'b',
ccc: 'c',
});
const data = [
{ caseName: 111, taskName: 111, userId: 'test', content: 'content', createTime: 'createTime' }
]
const data = {
data: [
{ caseName: 111, taskName: 111, userId: 'test1', content: 'content1', createTime: 'createTime1' },
{ caseName: 222, taskName: 222, userId: 'test2', content: 'content2', createTime: 'createTime2' },
{ caseName: 333, taskName: 333, userId: 'test3', content: 'content3', createTime: 'createTime3' }
],
total: 3
}
const prop = [
{
code: "caseName",
name: "案件名称",
i18n: 'table.props.0',
width: 110,
},
{
code: "taskName",
name: "任务名称",
i18n: 'table.props.1',
width: 110,
},
{
code: "userId",
name: "用户名",
i18n: 'table.props.2',
width: 100,
},
{
code: "content",
name: "日志内容",
i18n: 'table.props.3',
width: 500,
},
{
code: "createTime",
name: "产生时间",
i18n: 'table.props.4',
width: 170,
},
];

13
examples/view/home.vue

@ -1,15 +1,14 @@ @@ -1,15 +1,14 @@
<template>
<WkbTag>ssss</WkbTag>
<NoobTag>{{ t('title') }}</NoobTag>
<NoobTag type="success">{{ t('title') }}</NoobTag>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { WkbTag } from "noob";
import { NoobTag, Http } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { post } = Http.Axios2
const { state, commit, dispatch } = useStore();
onMounted(() => { });
</script>
<style lang="scss" scoped>
//@import url(); css

2
examples/view/tool/color.vue

@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { Color } from 'noob'
import { Color } from 'noob-mengyxu'
const { state, commit, dispatch } = useStore();

2
examples/view/tool/terminal.vue

@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
<script lang="ts" setup>
import { reactive, onMounted, ref } from "vue";
import { Terminal, TerminalSplit } from "noob";
import { Terminal, TerminalSplit } from "noob-mengyxu";
let index = 111;
const prefix = "ws://localhost/websocket/";

26
package.json

@ -1,11 +1,29 @@ @@ -1,11 +1,29 @@
{
"name": "noob-mengyxu",
"version": "0.2.0",
"version": "0.2.4",
"main": "index.ts",
"module": "index.ts",
"keywords": [
"noob-mengyxu",
"noob",
"mengyxu",
"component library",
"ui framework",
"ui",
"vue"
],
"file": [
"packages/",
"plugs/"
],
"exports": {
".": {
"require": "./index.ts",
"import": "./index.ts"
},
"./packages": "./packages/index.ts",
"./plugs": "./plugs/index.ts"
},
"scripts": {
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
@ -14,10 +32,11 @@ @@ -14,10 +32,11 @@
"dependencies": {
"axios": "^0.19.2",
"core-js": "^3.8.3",
"element-plus": "2.2.18",
"element-plus": "2.2.20",
"vue": "^3.2.25",
"vue-class-component": "^8.0.0-0",
"vue-router": "^4.0.3",
"vue3-i18n": "^1.1.5",
"vuex": "^4.0.0",
"xterm": "^5.2.1",
"xterm-addon-attach": "^0.8.0",
@ -31,7 +50,8 @@ @@ -31,7 +50,8 @@
"@vue/cli-service": "~5.0.0",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"typescript": "~4.5.5"
"typescript": "~4.5.5",
"js-md5": "^0.7.3"
},
"eslintConfig": {
"root": true,

58
packages/base/data/descriptions.vue

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
<template>
<el-descriptions class="noob-descriptions" :title="title" :column="colnums[state.size.size]" :size="state.size.size"
:border="border">
<el-descriptions-item v-if="isObi()" v-for="(val, key, i) in data" :label="key">
{{ val }}
</el-descriptions-item>
<el-descriptions-item v-else-if="isArr()" v-for="item in data" :label="item.key">
{{ item.value }}
</el-descriptions-item>
<el-descriptions-item v-else :label="t('base.value')">{{ data }}</el-descriptions-item>
</el-descriptions>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { onMounted } from "vue";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
const prop = defineProps({
data: {
type: Object,
default: 0,
},
title: {
type: String,
default: null,
},
border: {
type: Boolean,
default: true
}
});
const colnums = {
'normal': 4,
'small': 5,
'large': 3
}
const isObi = () => {
return typeof prop.data === 'object';
}
const isArr = () => {
return Array.isArray(prop.data);
}
onMounted(() => { });
</script>
<style lang="scss" scoped>
//@import url(); css
.noob-descriptions {
--el-descriptions-item-bordered-label-background: v-bind('state.style.tableBg') !important;
}
</style>

81
packages/base/data/infomation.vue

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
<template>
<div :class="['infomation', center && 'center']">
<el-button class="icon" type="info" :icon="icon"></el-button>
<div class="title">{{ title }}</div>
<el-divider></el-divider>
<span style="margin-right: -105px">{{ num }}</span>
</div>
</template>
<script lang="ts" setup>
const prop = defineProps({
num: {
type: Number,
default: 0,
},
icon: {
type: String,
default: '',
},
title: {
type: String,
default: '',
},
center: {
type: Boolean,
default: false
}
});
</script>
<style lang="scss" scoped>
.infomation {
text-align: center;
margin-bottom: 10px;
float: left;
width: 250px;
height: 80px;
background-color: transparent;
color: deepskyblue;
border-radius: 20px;
margin-left: 50px;
box-shadow: -2px 2px 3px #aaaaaa;
.icon {
position: relative;
top: -10px;
z-index: 2;
left: -35px;
font-size: 20px;
background-color: transparent;
color: deepskyblue;
}
.title {
float: right;
margin: 10px 10px 0 0;
}
&.center {
.icon {
left: 0px;
}
.title {
float: none;
width: 100%;
margin: 0;
text-align: center;
}
}
}
.el-divider {
background-color: transparent;
position: relative;
}
.el-divider--horizontal {
margin: 5px 0;
}
</style>

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

@ -0,0 +1,144 @@ @@ -0,0 +1,144 @@
<template>
<div class="my-table">
<el-table :size="state.size.size" :data="page ? data.data : data" @selection-change="selectionChange"
:height="height || (page ? state.size.pTableHeight : state.size.tableHeight)" highlight-current-row
:row-key="rowKey" :tree-porps="treeProps">
<el-table-column v-for="item in props" :key="item.code" :prop="item.code" :label="item.name || t(item.i18n)"
:type="item.type" :min-width="item.width" :width="item.type ? item.width : ''" :fixed="item.fixed"
:align="item.align ? item.align : 'center'" show-overflow-tooltip :formatter="formatter">
<template v-if="item.slot" #default="scope">
<slot :name="item.code" :row="scope.row"></slot>
</template>
<template v-if="item.dict" #default="{ row }">
{{ formatterByDist(item.dict, row[item.code]) }}
</template>
</el-table-column>
</el-table>
</div>
<div v-if="page" class="my-pagination">
<el-pagination :small="state.size.size == 'small'" @size-change="handleSizeChange"
@current-change="handleCurrentChange" :current-page="example.page" :page-sizes="[10, 20, 50, 100, 200]"
:page-size="example.size" layout="total, sizes, prev, pager, next, jumper" :total="data.total">
</el-pagination>
</div>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { useI18n } from "vue3-i18n";
// import { PageExample } from "noob-mengyxu";
const { t } = useI18n();
const { state } = useStore();
const prop = defineProps({
data: {
type: Object,
default: null
},
props: {
type: Array<any>(),
default: [],
},
page: {
type: Boolean,
default: false,
},
height: {
type: Number,
default: null,
},
example: {
type: Object,
default: {},
},
rowKey: {
type: String,
default: null,
},
treeProps: {
type: Object,
default: null,
},
});
const emit = defineEmits(["query", "selection-change"]);
const selectionChange = selection => {
emit("selection-change", selection);
};
const handleSizeChange = (val) => {
prop.example.size = val;
emit("query");
};
const handleCurrentChange = (val) => {
prop.example.page = val;
emit("query");
};
const getValue = (
row: any,
column: string,
value: any,
index?: number
) => {
if ((value == null || value == '') && value !== 0) {
return '--';
}
return value;
};
const formatter = (row: any, column: any, value: any, index: number) => {
if (row.scheme)
return formatterByDist(row.scheme + '_' + column.property, value);
return getValue(null, '', value);
};
const formatterByDist = (dictKey, value) => {
if (!dictKey) {
return getValue(null, '', value);
}
const mapping = state.dict[dictKey];
if (mapping == null) {
return getValue(null, '', value);
}
return mapping[value] == null ? value : mapping[value];
};
onMounted(() => { });
</script>
<style lang="scss" scoped>
.my-table * {
--el-table-bg-color: v-bind('state.style.tableBg') !important;
--el-table-tr-bg-color: v-bind('state.style.tableBg') !important;
--el-table-expanded-cell-bg-color: v-bind('state.style.tableBg') !important;
--el-table-border-color: v-bind('state.style.tableBorderColor');
--el-table-border: 1px solid var(--el-table-border-color);
--el-table-text-color: v-bind('state.style.tableColor');
--el-table-header-text-color: v-bind('state.style.tableColor');
--el-table-row-hover-bg-color: v-bind('state.style.tableCurBg');
--el-table-current-row-bg-color: v-bind('state.style.tableCurBg');
--el-table-header-bg-color: v-bind('state.style.tableHeadBg');
--el-bg-color: v-bind('state.style.tableBg') !important;
}
::v-deep .el-table__row--level-1,
::v-deep .el-table__row--level-3 {
background: v-bind('state.style.tableChildBg') !important;
}
.my-pagination * {
--el-pagination-bg-color: v-bind('state.style.bodyBg') !important;
--el-pagination-disabled-bg-color: v-bind('state.style.bodyBg') !important;
--el-pagination-text-color: v-bind('state.style.color') !important;
--el-pagination-button-color: v-bind('state.style.color') !important;
--el-pagination-button-disabled-bg-color: v-bind('state.style.bodyBg') !important;
}
</style>

68
packages/base/data/login-form.vue

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
<template>
<el-form label-position="right" class="login-form" :model="param" ref="loginForm" :rules="rules">
<el-form-item>
<div class="lte-title"> {{ t('title') }} </div>
</el-form-item>
<el-form-item prop="userId">
<NoobInput v-model="param.userId" :placeholder="t('pwd.userId')" :full="true"></NoobInput>
</el-form-item>
<el-form-item prop="password">
<NoobInput v-model="param.password" type="password" :placeholder="t('pwd.pwd')" :full="true"></NoobInput>
</el-form-item>
<el-form-item>
<NoobButton @click="login">{{ t('pwd.login') }}</NoobButton>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { FormInstance } from "element-plus";
import { NoobInput, NoobButton, Element } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state } = useStore();
const { SimpleRequired } = Element;
const emit = defineEmits(["login"]);
const param = ref<any>({});
const loginForm = ref<FormInstance>();
const rules = {
userId: [new SimpleRequired('pwd.userId')],
password: [new SimpleRequired('pwd.pwd')]
}
const login = () => {
if (!loginForm.value) return;
loginForm.value?.validate((valid, fields) => {
if (valid) {
emit("login", param.value);
loginForm.value?.clearValidate();
}
});
}
onMounted(() => { });
</script>
<style lang="scss" scoped>
//@import url(); css
.login-form {
width: v-bind('state.size.loginWidth');
height: v-bind('state.size.loginHeight');
}
.lte-title {
font-size: 1.5em;
font-weight: bold;
text-align: center;
width: 100%;
color: rgb(49, 89, 143);
}
.el-button {
width: 100%;
}
</style>

26
packages/base/form/modify-form.vue → packages/base/data/modify-form.vue

@ -2,10 +2,19 @@ @@ -2,10 +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" v-model="param[item.code]" :dict="item.dict" 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"
:placeholder="t('rule.pleaseEnter') + (item.name || t(item.i18n))" :disabled="item.disabled" />
</el-form-item>
<slot></slot>
<el-form-item class="form-btns">
<el-button type="primary" @click="formConfirm">确定</el-button>
<el-button type="info" @click="emit('cancel')">取消</el-button>
<NoobButton type="primary" @click="formConfirm">{{ t('base.confirm') }}</NoobButton>
<NoobButton type="info" @click="emit('cancel')">{{ t('base.cancel') }}</NoobButton>
</el-form-item>
</el-form>
</div>
@ -14,6 +23,9 @@ @@ -14,6 +23,9 @@
<script lang="ts" setup>
import { onMounted, ref, watch } from "vue";
import { FormInstance } from "element-plus";
import { useI18n } from 'vue3-i18n';
import { NoobSelect, NoobInput, NoobDate, NoobButton } from "noob-mengyxu";
const { t } = useI18n();
const prop = defineProps({
width: {
@ -32,6 +44,14 @@ const prop = defineProps({ @@ -32,6 +44,14 @@ const prop = defineProps({
type: String,
default: '',
},
type: {
type: String,
default: null,
},
items: {
type: Array<any>(),
default: [],
},
});
const emit = defineEmits(["confirm", "cancel"]);
const modifyForm = ref<FormInstance>();
@ -54,6 +74,8 @@ watch(() => prop.param, () => { @@ -54,6 +74,8 @@ watch(() => prop.param, () => {
modifyForm.value?.clearValidate();
});
defineExpose({ clearValidate })
onMounted(() => {
});
</script>

24
packages/base/table/search-row.vue → packages/base/data/search-row.vue

@ -2,16 +2,20 @@ @@ -2,16 +2,20 @@
<div class="search-row">
<div class="left">
<span class="title" v-if="title">{{ title }}</span>
<el-button :size="state.size.size" v-if="fresh" type="info" icon="Refresh" @click="emit('query')"> </el-button>
<el-button :size="state.size.size" v-if="add" type="primary" icon="Plus" @click="emit('add')"> 添加 </el-button>
<el-button :size="state.size.size" v-if="del" type="danger" icon="Delete" @click="emit('delete')"> 删除
</el-button>
<NoobButton v-if="fresh" type="info" icon="Refresh" @click="emit('query')"> </NoobButton>
<NoobButton v-if="add" type="primary" icon="Plus" @click="emit('add')">
{{ t('base.add') }}
</NoobButton>
<NoobButton v-if="del" type="danger" icon="Delete" @click="emit('delete')">
{{ t('base.delete') }}
</NoobButton>
<slot name="left"></slot>
</div>
<div class="query">
<slot></slot>
<el-button :size="state.size.size" v-if="query" type="primary" icon="Search" @click="emit('query')"> 查询
</el-button>
<NoobButton v-if="query" type="primary" icon="Search" @click="emit('query')">
{{ t('base.select') }}
</NoobButton>
</div>
</div>
</template>
@ -19,6 +23,9 @@ @@ -19,6 +23,9 @@
<script lang="ts" setup>
import { onMounted } from "vue";
import { useStore } from "vuex";
import { useI18n } from 'vue3-i18n';
import { NoobButton } from 'noob-mengyxu';
const { t } = useI18n();
const { state } = useStore();
const prop = defineProps({
title: {
@ -55,14 +62,15 @@ onMounted(() => { }); @@ -55,14 +62,15 @@ onMounted(() => { });
}
.query {
// align-items: right;
text-align: right;
float: right;
width: 50%;
// width: 50%;
}
.left {
float: left;
width: 50%;
// width: 50%;
}
.search-row,

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

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
<template>
<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>
<el-tooltip effect="dark" :content="t('base.delete')" placement="top">
<el-button v-if="del" :size="state.size.size" type="danger" @click="emit('del')" icon="delete" circle />
</el-tooltip>
<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>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { onMounted } from "vue";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state } = useStore();
const emit = defineEmits(["modify", "del", "add"]);
const prop = defineProps({
add: {
type: Boolean,
default: false,
},
modify: {
type: Boolean,
default: true,
},
del: {
type: Boolean,
default: true,
},
});
onMounted(() => { });
</script>
<style lang="scss" scoped>
//@import url(); css
</style>

32
packages/base/index.ts

@ -1,12 +1,24 @@ @@ -1,12 +1,24 @@
import WkbTag from './tag.vue';
import NoobTag from './item/tag.vue';
import NoobButton from './item/button.vue';
import NoobSelect from './item/select.vue';
import NoobInput from './item/input.vue';
import NoobDate from './item/datetime.vue';
export { WkbTag };
export { NoobTag, NoobButton, NoobSelect, NoobInput, NoobDate };
import SearchRow from './table/search-row.vue';
import SearchInput from './table/search-input.vue';
import ListTable from './table/list-table.vue';
export { SearchRow, ListTable, SearchInput };
import ModifyForm from './form/modify-form.vue';
import DictSelect from './form/dict-select.vue';
export { ModifyForm, DictSelect };
import SearchRow from './data/search-row.vue';
import ListTable from './data/list-table.vue';
import Infomation from './data/infomation.vue';
import ModifyForm from './data/modify-form.vue';
import LoginForm from './data/login-form.vue';
import Descriptions from './data/descriptions.vue';
import TableAction from './data/table-action.vue';
export {
SearchRow,
ListTable,
Infomation,
ModifyForm,
LoginForm,
Descriptions,
TableAction,
};

64
packages/base/item/button.vue

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
<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">
<slot />
</el-button>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
const { state } = useStore();
const prop = defineProps({
type: {
type: String,
default: null
},
icon: {
type: String,
default: null
},
disabled: {
type: Boolean,
default: false,
},
plain: {
type: Boolean,
default: false,
},
round: {
type: Boolean,
default: false,
},
circle: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
text: {
type: Boolean,
default: false,
},
link: {
type: Boolean,
default: false,
}
});
onMounted(() => { });
</script>
<style lang="scss" scoped>
//@import url(); css
.dark {
--el-button-bg-color: v-bind('state.style.itemBg');
--el-button-border-color: v-bind('state.style.itemBg');
--el-button-text-color: v-bind('state.style.color');
--el-button-hover-bg-color: v-bind('state.style.itemBg');
--el-button-hover-border-color: v-bind('state.style.itemBg');
--el-button-hover-text-color: v-bind('state.style.color');
}
</style>

69
packages/base/item/datetime.vue

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
<template>
<el-date-picker :size="state.size.size" :class="['form-item', full && 'full']" :value-format="formater"
v-model="myValue" type="datetime" :placeholder="placeholder || t('rule.pleaseEnter')" :disabled="disabled"
:clearable="clearable" :teleported="false" />
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { onMounted, ref, watch } from "vue";
import { useI18n } from 'vue3-i18n';
const { t } = useI18n();
const { state } = useStore();
const prop = defineProps({
modelValue: null,
placeholder: {
type: String,
default: null
},
disabled: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: true,
},
full: {
type: Boolean,
default: false,
},
formater: {
type: String,
defaul: 'YYYY-MM-DDTHH:mm:ss'
},
width: {
type: Number
}
});
const emit = defineEmits(["update:modelValue"]);
const myValue = ref(null);
const width = ref('150px');
const setWidth = () => {
if (prop.width) {
width.value = prop.width + 'px';
} else {
width.value = state.size.searchWidth;
}
}
watch(() => state.size, (n, o) => {
setWidth();
})
watch(myValue, (n, o) => {
emit('update:modelValue', n);
})
watch(() => prop.modelValue, (n, o) => {
myValue.value = n;
})
onMounted(() => {
prop.modelValue && (myValue.value = prop.modelValue);
setWidth();
});
</script>
<style lang="scss">
//@import url(); css
.form-item {
width: v-bind('width');
}
</style>

68
packages/base/item/input.vue

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
<template>
<el-input :size="state.size.size" :class="['form-item', full && 'full']" v-model="myValue" :type="type"
:placeholder="placeholder || t('rule.pleaseEnter')" :disabled="disabled" :clearable="clearable"></el-input>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { onMounted, ref, watch } from "vue";
import { useI18n } from 'vue3-i18n';
const { t } = useI18n();
const { state } = useStore();
const prop = defineProps({
modelValue: null,
placeholder: {
type: String,
default: null
},
type: {
type: String,
default: null
},
disabled: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: true,
},
full: {
type: Boolean,
default: false,
},
width: {
type: Number
}
});
const emit = defineEmits(["update:modelValue"]);
const myValue = ref(null);
const width = ref('150px');
const setWidth = () => {
if (prop.width) {
width.value = prop.width + 'px';
} else {
width.value = state.size.searchWidth;
}
}
watch(myValue, (n, o) => {
emit('update:modelValue', n);
})
watch(() => prop.modelValue, (n, o) => {
myValue.value = n;
})
watch(() => state.size, (n, o) => {
setWidth();
})
onMounted(() => {
prop.modelValue && (myValue.value = prop.modelValue);
setWidth();
});
</script>
<style lang="scss" scoped>
//@import url(); css
.form-item {
width: v-bind('width');
}
</style>

62
packages/base/form/dict-select.vue → packages/base/item/select.vue

@ -1,16 +1,20 @@ @@ -1,16 +1,20 @@
<template>
<el-select :size="state.size.size" class="dict-select" v-model="myValue" :placeholder="placeholder"
:filterable="filterable" :disabled="disabled" :clearable="clearable" @change="$emit('change', myValue)"
:teleported="false">
<el-select :size="state.size.size" :class="['form-item', full && 'full']" v-model="myValue"
:placeholder="placeholder || t('rule.pleaseSelect')" :filterable="filterable" :disabled="disabled"
:clearable="clearable" @change="$emit('change', myValue)" :teleported="false">
<el-option v-if="dict" v-for="(val, key, i) in state.dict[dict]" :key="key" :value="key" :label="val" />
<el-option v-if="stateProp" v-for="item in state[stateProp]" :key="item[valueKey]" :value="item[valueKey]"
:label="item[labelKey]" />
<el-option v-if="maxValue" v-for="index in maxValue" :key="index" :value="index" />
<slot />
</el-select>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref, watch } from "vue";
import { onMounted, ref, watch } from "vue";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state } = useStore();
const prop = defineProps({
@ -30,9 +34,12 @@ const prop = defineProps({ @@ -30,9 +34,12 @@ const prop = defineProps({
type: Boolean,
default: true,
},
full: {
type: Boolean,
default: false,
},
width: {
type: Number,
default: 150,
type: Number
},
dict: {
type: String
@ -40,6 +47,9 @@ const prop = defineProps({ @@ -40,6 +47,9 @@ const prop = defineProps({
stateProp: {
type: String
},
maxValue: {
type: Number
},
valueKey: {
type: String,
default: 'key'
@ -50,40 +60,34 @@ const prop = defineProps({ @@ -50,40 +60,34 @@ const prop = defineProps({
},
});
const emit = defineEmits(["update:modelValue"]);
const myValue = ref(null);
const myValue = ref<any>(null);
const width = ref('150px');
const setWidth = () => {
if (prop.width) {
width.value = prop.width + 'px';
} else {
width.value = state.size.searchWidth;
}
}
watch(() => state.size, (n, o) => {
setWidth();
})
watch(myValue, (n, o) => {
emit('update:modelValue', n);
})
watch(() => prop.modelValue, (n, o) => {
myValue.value = n;
})
onMounted(() => {
myValue.value = prop.modelValue;
width.value = prop.width + 'px';
prop.modelValue && (myValue.value = prop.modelValue);
setWidth();
});
onMounted(() => { });
</script>
<style lang="scss" scoped>
//@import url(); css
.dict-select {
.form-item {
width: v-bind('width');
margin-right: v-bind('state.size.searchMargin');
::v-deep .el-input__wrapper,
::v-deep .el-select-dropdown {
background-color: v-bind('state.style.itemBg');
.el-input__inner,
.el-select-dropdown__item {
color: v-bind('state.style.color');
&.selected{
color: v-bind('state.style.itemSelectColor') !important;
}
}
.el-select-dropdown__item.hover,
.el-select-dropdown__item:hover {
background-color: v-bind('state.style.bodyBg');
}
}
}
</style>

24
packages/base/tag.vue → packages/base/item/tag.vue

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<template>
<span :class="['wkb-tag', type]">
<el-tag :size="state.size.size" :type="type" :color="color" :closable="closable" :round="round" :effect="state.style.name">
<slot />
</span>
</el-tag>
</template>
<script lang="ts" setup>
@ -12,8 +12,24 @@ const { state, commit, dispatch } = useStore(); @@ -12,8 +12,24 @@ const { state, commit, dispatch } = useStore();
const prop = defineProps({
type: {
type: String,
default: 'primary'
}
default: null
},
color: {
type: String,
default: null
},
closable: {
type: Boolean,
default: false,
},
round: {
type: Boolean,
default: false,
},
effect: {
type: String,
default: 'light',
},
});
onMounted(() => { });

116
packages/base/table/list-table.vue

@ -1,116 +0,0 @@ @@ -1,116 +0,0 @@
<template>
<div class="my-table">
<el-table :size="state.size.size" :data="page ? data.data : data" @selection-change="selectionChange"
:height="height ? height : (page ? state.sizes.pTableHei : state.sizes.tableHei)" highlight-current-row
header-row-class-name="table-head" row-class-name="table-row">
<el-table-column v-for="item in props" :key="item.code" :prop="item.code" :label="item.name" :type="item.type"
:min-width="item.width" :width="item.type ? item.width : ''" :align="item.align ? item.align : 'center'"
show-overflow-tooltip :formatter="formatter">
<template v-if="item.slot" #default="scope">
<slot :name="item.code" :row="scope.row"></slot>
</template>
</el-table-column>
</el-table>
</div>
<div v-if="page" class="my-pagination">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="example.page"
:page-sizes="[10, 20, 50, 100, 200]" :page-size="example.size" layout="total, sizes, prev, pager, next, jumper"
:total="data.total">
</el-pagination>
</div>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
const { state } = useStore();
const prop = defineProps({
data: {
type: Object,
default: null
},
props: {
type: Array<any>(),
default: [],
},
page: {
type: Boolean,
default: false,
},
height: {
type: Number,
default: null,
},
example: {
type: Object,
default: null,
},
});
const emit = defineEmits(["query", "selection-change"]);
const selectionChange = selection => {
emit("selection-change", selection);
};
const handleSizeChange = (val) => {
prop.example.size = val;
emit("query");
};
const handleCurrentChange = (val) => {
prop.example.page = val;
emit("query");
};
const getValue = (
row: any,
column: string,
value: any,
index?: number
) => {
if ((value == null || value == '') && value !== 0) {
return '--';
}
return value;
};
const formatter = (row: any, column: any, value: any, index: number) => {
if (row.scheme)
return formatterByDist(row.scheme + '_' + column.property, value);
return getValue(null, '', value);
};
const formatterByDist = (dictKey, value) => {
if (!dictKey) {
return getValue(null, '', value);
}
const mapping = state.dict[dictKey];
if (mapping == null) {
return getValue(null, '', value);
}
return mapping[value] == null ? value : mapping[value];
};
onMounted(() => { });
</script>
<style lang="scss" scoped>
//@import url(); css
.my-table ::v-deep .el-table__header .el-table__cell {
background-color: v-bind('state.style.tableHeadBg') !important;
border-bottom: 1px solid v-bind('state.style.tableBorderColor');
}
.my-table ::v-deep .el-table {
background-color: v-bind('state.style.bodyBg') !important;
color: v-bind('state.style.tableColor');
border-bottom: 1px solid v-bind('state.style.tableBorderColor');
}
.my-table ::v-deep .el-table__body .el-table__cell {
background-color: v-bind('state.style.tableBg') !important;
border-bottom: 1px solid v-bind('state.style.tableBorderColor');
}
</style>

51
packages/base/table/search-input.vue

@ -1,51 +0,0 @@ @@ -1,51 +0,0 @@
<template>
<el-input :size="state.size.size" class="search-input" v-model="myValue" :placeholder="placeholder || state.lang.pleaseEnter"
:disabled="disabled" :clearable="clearable"></el-input>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref, watch } from "vue";
const { state, commit, dispatch } = useStore();
const prop = defineProps({
modelValue: null,
placeholder: {
type: String,
default: null
},
disabled: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: true,
},
width: {
type: Number,
default: 150,
}
});
const emit = defineEmits(["update:modelValue"]);
const myValue = ref(null);
const width = ref('150px');
watch(myValue, (n, o) => {
emit('update:modelValue', n);
})
onMounted(() => {
myValue.value = prop.modelValue;
width.value = prop.width + 'px';
});
</script>
<style lang="scss" scoped>
//@import url(); css
.search-input {
width: v-bind('width');
margin-right: v-bind('state.size.searchMargin');
::v-deep .el-input__wrapper{
background-color: v-bind('state.style.itemBg');
}
}
</style>

116
packages/manage/components/head.vue → packages/manage/common/head.vue

@ -1,42 +1,45 @@ @@ -1,42 +1,45 @@
<template>
<div class="head">
<div class="title">{{ title || state.lang.title }}</div>
<div class="title">{{ title || t('title') }}</div>
<div class="menu">
<el-dropdown class="icon" :size="state.size.size">
<el-dropdown class="icon" :size="state.size.size" :teleported="false">
<el-button :size="state.size.size" icon="Avatar" circle></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="updatePass">{{ state.lang.changePwd }}</el-dropdown-item>
<el-dropdown-item @click="emit('logout')">{{ state.lang.logout }}</el-dropdown-item>
<el-dropdown-item v-if="center" @click="router.push(center)">
{{ 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-menu>
</template>
</el-dropdown>
<el-tooltip class="box-item" effect="dark" :content="state.lang.fullScreen" placement="bottom">
<el-tooltip effect="dark" :content="t('head.fullScreen')" placement="bottom">
<el-icon @click="fullscreen" class="icon">
<FullScreen />
</el-icon>
</el-tooltip>
<el-tooltip class="box-item" effect="dark" :content="state.lang.changeStyle" placement="left">
<el-dropdown class="icon" :size="state.size.size" trigger="click">
<el-tooltip effect="dark" :content="t('head.changeStyle')" placement="left">
<el-dropdown v-show="styleAble" class="icon" :size="state.size.size" trigger="click" :teleported="false">
<el-button :size="state.size.size" icon="Opportunity" circle></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="changeStyle('noobStyle')">
<el-tooltip class="box-item" effect="dark" :content="state.lang.default" placement="left">
<el-dropdown-item @click="changeStyle('plain')">
<el-tooltip effect="dark" :content="t('head.default')" placement="left">
<el-icon class="dropdown-icon">
<Sunset />
</el-icon>
</el-tooltip>
</el-dropdown-item>
<el-dropdown-item @click="changeStyle('light')">
<el-tooltip class="box-item" effect="dark" :content="state.lang.light" placement="left">
<el-tooltip effect="dark" :content="t('head.light')" placement="left">
<el-icon class="dropdown-icon">
<Sunny />
</el-icon>
</el-tooltip>
</el-dropdown-item>
<el-dropdown-item @click="changeStyle('dark')">
<el-tooltip class="box-item" effect="dark" :content="state.lang.dark" placement="left">
<el-tooltip effect="dark" :content="t('head.dark')" placement="left">
<el-icon class="dropdown-icon">
<MoonNight />
</el-icon>
@ -46,25 +49,25 @@ @@ -46,25 +49,25 @@
</template>
</el-dropdown>
</el-tooltip>
<el-tooltip class="box-item" effect="dark" :content="state.lang.language" placement="left">
<el-dropdown class="icon" :size="state.size.size" trigger="click">
<el-tooltip effect="dark" :content="t('head.language')" placement="left">
<el-dropdown v-show="langAble" class="icon" :size="state.size.size" trigger="click" :teleported="false">
<el-button icon="Flag" :size="state.size.size" circle></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="changeLang('chinese')">简体中文</el-dropdown-item>
<el-dropdown-item @click="changeLang('english')">English</el-dropdown-item>
<el-dropdown-item @click="changeLang('zh')">{{ t('head.zh') }}</el-dropdown-item>
<el-dropdown-item @click="changeLang('en')">{{ t('head.en') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-tooltip>
<el-tooltip class="box-item" effect="dark" :content="state.lang.size" placement="left">
<el-dropdown class="icon" :size="state.size.size" trigger="click">
<el-tooltip effect="dark" :content="t('head.size')" placement="left">
<el-dropdown v-show="sizeAble" class="icon" :size="state.size.size" trigger="click" :teleported="false">
<el-button icon="Switch" :size="state.size.size" circle></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="changeSize('normal')">{{ state.lang.normal }}</el-dropdown-item>
<el-dropdown-item @click="changeSize('small')">{{ state.lang.small }}</el-dropdown-item>
<el-dropdown-item @click="changeSize('large')">{{ state.lang.large }}</el-dropdown-item>
<el-dropdown-item @click="changeSize('small')">{{ t('head.small') }}</el-dropdown-item>
<el-dropdown-item @click="changeSize('normal')">{{ t('head.normal') }}</el-dropdown-item>
<el-dropdown-item @click="changeSize('large')">{{ t('head.large') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@ -72,19 +75,10 @@ @@ -72,19 +75,10 @@
</div>
</div>
<el-dialog :title="state.lang.changePwd" v-model="flag.update" :size="state.size.size" :close-on-click-modal="false"
<el-dialog :title="t('pwd.changePwd')" v-model="flag.update" :size="state.size.size" :close-on-click-modal="false"
top="10vh" width="40%">
<ModifyForm :width="150" :param="password" @cancel="flag.update = false" @confirm="emit('updatePwd', password)"
:rules="rules">
<el-form-item :label="state.lang.oldPwd" prop="old">
<el-input v-model="password.old"></el-input>
</el-form-item>
<el-form-item :label="state.lang.newPwd" prop="new">
<el-input v-model="password.new"></el-input>
</el-form-item>
<el-form-item :label="state.lang.rePwd" prop="reNew">
<el-input v-model="password.reNew"></el-input>
</el-form-item>
:rules="rules" :items="items">
</ModifyForm>
</el-dialog>
</template>
@ -92,13 +86,16 @@ @@ -92,13 +86,16 @@
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { ModifyForm } from "noob";
import { setLang } from "plugs";
import { SimpleRequired, SimplePassword } from 'plugs/element'
import { lang, styles, size } from 'plugs/config'
import { ModifyForm } from "noob-mengyxu";
import { Element, Styles, Size, NoobInput } from "noob-mengyxu";
import { useRouter } from "vue-router";
import { useI18n } from "vue3-i18n";
const { SimpleRequired, SimplePassword } = Element;
const { state, commit, dispatch } = useStore();
const router = useRouter();
const i18n = useI18n();
const { t } = useI18n();
const emit = defineEmits(["updatePwd", "logout"]);
const flag = reactive({
update: false
@ -113,35 +110,45 @@ const props = defineProps({ @@ -113,35 +110,45 @@ const props = defineProps({
title: {
type: String,
default: null,
}
},
styleAble: {
type: Boolean,
},
sizeAble: {
type: Boolean,
},
langAble: {
type: Boolean,
},
center: {
type: String,
default: null,
},
});
const rules = {
old: [{
required: true,
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback(new Error(state.lang.pleaseEnter + state.lang.oldPwd.toLowerCase()));
}
callback();
}
}],
new: [new SimplePassword()],
old: [new SimpleRequired('pwd.oldPwd')],
new: [new SimpleRequired('pwd.newPwd'), new SimplePassword()],
reNew: [{
required: true,
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback(new Error(state.lang.plsRePwd));
callback(new Error(t('pwd.plsRePwd')));
} else if (value != password.value.new) {
callback(new Error(state.lang.rePwdError));
callback(new Error(t('pwd.rePwdError')));
}
callback();
}
}]
}
const items = [
{ i18n: 'pwd.oldPwd', code: 'old', type: "password" },
{ i18n: 'pwd.newPwd', code: 'new', type: "password" },
{ i18n: 'pwd.rePwd', code: 'reNew', type: "password" },
]
const updatePass = () => {
password.value = {
new: '',
@ -162,17 +169,16 @@ const fullscreen = () => { @@ -162,17 +169,16 @@ const fullscreen = () => {
}
const changeStyle = type => {
commit('updateState', { prop: 'style', value: styles[type] })
commit('updateState', ['style', Styles[type]]);
}
const changeLang = type => {
const newLang = lang[type];
setLang(newLang);
commit('updateState', { prop: 'lang', value: newLang })
i18n.setLocale(type);
}
const changeSize = type => {
commit('updateState', { prop: 'size', value: size[type] })
commit('updateState', ['size', Size[type]])
commit('initSize', window.innerHeight);
}
onMounted(() => { });

34
packages/manage/components/menuTree.vue → packages/manage/common/menu-tree.vue

@ -5,15 +5,19 @@ @@ -5,15 +5,19 @@
<template v-if="menu.children && menu.children.length > 0">
<el-sub-menu :index="menu.path" :key="menu.path">
<template #title>
<span>{{ menu.title ? menu.title : defTitle }}</span>
<component class="icon" :is="menu.icon || state.style.menuDefaultIcon"></component>
<span>{{ menu.title || t(menu.i18n) }}</span>
</template>
<el-menu-item v-for="child in menu.children" :index="child.path" :router="router">{{ child.title
}}</el-menu-item>
<el-menu-item v-for="child in menu.children" :index="child.path" :router="router">
<component class="icon" :is="child.icon || state.style.menuDefaultIcon"></component>
{{ child.title || t(child.i18n) }}
</el-menu-item>
</el-sub-menu>
</template>
<template v-else>
<el-menu-item :index="menu.path" :key="menu.path" :router="router">
<span>{{ menu.title ? menu.title : defTitle }}</span>
<component class="icon" :is="menu.icon || state.style.menuDefaultIcon"></component>
<span>{{ menu.title || t(menu.i18n) }}</span>
</el-menu-item>
</template>
</template>
@ -23,6 +27,8 @@ @@ -23,6 +27,8 @@
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { ref, onMounted } from "vue"
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state } = useStore()
const props = defineProps({
@ -33,10 +39,6 @@ const props = defineProps({ @@ -33,10 +39,6 @@ const props = defineProps({
type: {
type: String,
default: 'def',
},
active: {
type: String,
default: 'home',
}
});
@ -49,7 +51,9 @@ const active = ref(""); @@ -49,7 +51,9 @@ const active = ref("");
const defTitle = "";
onMounted(() => {
active.value = props.active;
setTimeout(() => {
active.value = router.currentRoute.value.path.substring(1);
}, 200);
router.push(active.value);
})
@ -58,15 +62,23 @@ onMounted(() => { @@ -58,15 +62,23 @@ onMounted(() => {
<style scoped lang="scss">
.menu-tree {
padding-top: 1px;
height: 100%;
height: v-bind('state.size.mainHeight');
border: none;
}
.icon {
// margin-left: -15px;
margin-right: 10px;
width: v-bind('state.size.menuIconSize');
height: v-bind('state.size.menuIconSize');
}
.el-menu-item.is-active {
background-color: v-bind('state.style.menuActiveBg');
}
.el-sub-menu .el-menu-item {
.el-sub-menu,
.el-menu-item {
min-width: v-bind('state.size.asideWidth') !important;
font-size: v-bind('state.size.fontSize') !important;
}

7
packages/manage/index.ts

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
import Index from './router/index.vue';
import MenuTree from './components/menuTree.vue';
import Head from './components/head.vue';
export { Index, MenuTree, Head };
import MenuTree from './common/menu-tree.vue';
import Head from './common/head.vue';
import Views from './views';
export { Index, MenuTree, Head, Views };

97
packages/manage/router/index.vue

@ -1,11 +1,12 @@ @@ -1,11 +1,12 @@
<template>
<el-container :style="appMain" ref="main">
<el-header v-show="flag.showHeader" class="app-head" :height="state.size.headHeight">
<el-header v-show="state.size.headHeight != '0px'" class="app-head" :height="state.size.headHeight">
<Head :title="title || state.lang.title" @updatePwd="pwd => emit('updatePwd', pwd)" @logout="emit('logout')" />
<Head :title="title" @updatePwd="pwd => emit('updatePwd', pwd)" @logout="onLogout" :styleAble="styleAble"
:sizeAble="sizeAble" :langAble="langAble" :center="center" />
</el-header>
<el-container id="container">
<el-aside v-show="flag.showAside" :width="state.size.asideWidth">
<el-aside v-show="state.size.asideWidth != '0px'" :width="state.size.asideWidth">
<MenuTree :data="menus" :type="type" />
</el-aside>
<el-main class="app-main">
@ -19,15 +20,14 @@ @@ -19,15 +20,14 @@
import { reactive, onMounted, ref } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { MenuTree, Head } from "noob"
import { MenuTree, Head, Api } from "noob-mengyxu"
const { state, commit } = useStore();
const { state, commit, dispatch } = useStore();
const emit = defineEmits(['updatePwd', 'logout']);
const router = useRouter()
const appMain = reactive({
height: window.innerHeight + 'px',
backgroundColor: state.style.bodyBg
// backgroundImage: "url(" + publik.background + ")",
});
const main = ref();
const flag = reactive({
@ -47,16 +47,52 @@ const props = defineProps({ @@ -47,16 +47,52 @@ const props = defineProps({
type: {
type: String,
default: 'def',
}
},
styleAble: {
type: Boolean,
default: true,
},
sizeAble: {
type: Boolean,
default: true,
},
langAble: {
type: Boolean,
default: true,
},
center: {
type: String,
default: 'home',
},
});
const onResize = () => {
appMain.height = window.innerHeight + 'px';
const height = window.innerHeight;
appMain.height = height + 'px';
commit('initSize', height);
}
const getUser = () => {
Api.pub.getInfo().then((rsp) => {
if (rsp) {
commit('updateState', ['user', rsp]);
} else {
router.push('/login');
}
});
};
const onLogout = () => {
Api.pub.logout().then(rsp => {
getUser();
});
}
onMounted(() => {
router.push("/")
getUser();
window.onresize = onResize;
onResize();
});
</script>
@ -64,11 +100,22 @@ onMounted(() => { @@ -64,11 +100,22 @@ onMounted(() => {
<style lang='scss'>
@charset "UTF-8";
body {
font-size: v-bind('state.size.fontSize') !important;
font-family: "Microsoft YaHei";
width: 100%;
height: 100%;
overflow: hidden;
padding: 0px;
margin: 0px;
}
.app-main {
box-shadow: 2px 2px 5px 3px #e5e6eb;
border-radius: 4px;
margin: 3px 0px 0px 3px !important;
padding: 5px !important;
padding: v-bind('state.size.mainPad') !important;
height: v-bind('state.size.mainHeight');
}
.el-header,
@ -88,4 +135,36 @@ onMounted(() => { @@ -88,4 +135,36 @@ onMounted(() => {
.app-head {
padding: 0px !important;
}
.form-item {
margin-right: v-bind('state.size.searchMargin');
&.full {
width: 100%;
margin-right: 0px;
}
}
#app {
.el-input {
--el-input-bg-color: v-bind('state.style.itemBg') !important;
--el-input-text-color: v-bind('state.style.color') !important;
}
.el-popper {
--el-bg-color-overlay: v-bind('state.style.itemBg') !important;
--el-fill-color-light: v-bind('state.style.bodyBg') !important;
text-align: left;
}
.el-dialog {
--el-dialog-bg-color: v-bind('state.style.bodyBg') !important;
}
* {
--el-text-color-regular: : v-bind('state.style.color') !important;
--el-text-color-primary: v-bind('state.style.color') !important;
}
}
</style>

56
packages/manage/views/buffer.vue

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
<template>
<SearchRow :title="t('buffer.title')" :del="false" @query="query" :add="false" :query="false">
<template #left>
<NoobButton type="success" :icon="delete" @click="clean().then(query)">
{{ t('buffer.clean') }}
</NoobButton>
</template>
</SearchRow>
<ListTable @query="query" :props="props" :data="result">
<template #value="{ row }">
<Descriptions :data="row.value" />
</template>
<template #action="{ row }">
<TableAction @modify="delay(row)" @del="delate(row)" />
</template>
</ListTable>
</template>
<script lang="ts" setup>
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 { prompt } = Element;
const { list, clean, set, del } = Api.buffer;
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.4', code: 'action', width: 130, slot: true },
]
const query = () => {
list().then((rsp: any) => result.value = rsp)
}
const delate = (row) => {
Element.confirm(t('buffer.delete.0'), t('buffer.delete.1')).then(() => {
del(row).then(query);
})
}
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)
})
}
onMounted(() => {
query();
});
</script>
<style lang="scss" scoped></style>

14
packages/manage/views/config.vue

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
<template>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
const { state, commit, dispatch } = useStore();
onMounted(() => {});
</script>
<style lang="scss" scoped>
//@import url(); css
</style>

115
packages/manage/views/dictionary.vue

@ -0,0 +1,115 @@ @@ -0,0 +1,115 @@
<template>
<SearchRow :title="t('dict.title')" :del="false" @query="query" @add="addDict">
<NoobInput v-model="example.name" :placeholder="t('dict.example.0')" />
<NoobInput v-model="example.code" :placeholder="t('dict.example.1')" />
<NoobSelect v-model="example.status" dict="active_status" :placeholder="t('dict.example.2')" />
</SearchRow>
<ListTable @query="query" :props="props" :example="example" :page="true" :data="result" rowKey="code"
:treeProps="{ children: 'children' }">
<template #status="{ row }">
<div slot="reference" class="name-wrapper">
<NoobTag v-if="row.status == 'A'">
{{ t('base.active') }}
</NoobTag>
<NoobTag v-else type="danger">
{{ t('base.inactive') }}
</NoobTag>
</div>
</template>
<template #action="{ row }">
<TableAction :add="row.parent == null" @modify="modify(row)" @del="delate(row)" @add="addDict(row)"/>
</template>
</ListTable>
<el-dialog :title="t('base.add') + t('dict.name')" v-model="flag.modify" :close-on-click-modal="false" top="15vh"
width="40%" @keydown.enter.native="confirm">
<ModifyForm ref="form" :param="dict" :rules="rules" :items="items" @confirm="confirm" @cancel="flag.modify = false">
<template #code>
<NoobInput v-model="dict.code" full :placeholder="t('rule.pleaseEnter') + t('dict.prop.1')"
:disabled="!flag.add" />
</template>
</ModifyForm>
</el-dialog>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { Api, PageExample, PageResult, ListTable, SearchRow, NoobInput, NoobSelect, TableAction, NoobTag, ModifyForm, Element } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { SimpleRequired } = Element;
const { state, commit, dispatch } = useStore();
const { list, add, set, del } = Api.dictionary;
const result = ref(new PageResult());
const example = reactive<any>(new PageExample());
const flag = reactive({
modify: false,
add: false
})
const dict = ref<any>();
const form = ref();
const props = [
{ i18n: 'dict.prop.0', code: 'name', width: 180, align: 'left' },
{ i18n: 'dict.prop.1', code: 'code', width: 180 },
{ i18n: 'dict.prop.2', code: 'desc', width: 300 },
{ i18n: 'dict.prop.3', code: 'status', slot: true, width: 120 },
{ i18n: 'dict.prop.4', code: 'action', slot: true, type: 'action', width: 180, fixed: 'right' },
]
const items = [
{ i18n: 'dict.prop.1', code: 'code', slot: true },
{ i18n: 'dict.prop.0', code: 'name' },
{ i18n: 'dict.prop.2', code: 'desc' },
{ i18n: 'dict.prop.3', code: 'status', dict: 'active_status' },
]
const rules = {
code: [new SimpleRequired('dict.prop.1')],
name: [new SimpleRequired('dict.prop.0')],
status: [new SimpleRequired('dict.prop.3')]
}
const query = () => {
list(example).then((rsp: any) => result.value = rsp)
}
const addDict = (row) => {
form.value?.clearValidate();
flag.modify = true;
flag.add = true;
dict.value = { status: 'A' }
row && (dict.value.parent = row.code);
}
const modify = (row) => {
form.value?.clearValidate();
flag.modify = true;
flag.add = false;
dict.value = JSON.parse(JSON.stringify(row));
}
const delate = (row) => {
Element.confirm(t('dict.delete.0'), t('dict.delete.1')).then(() => {
del(row).then(query);
})
}
const confirm = () => {
const api = flag.add ? add : set;
api(dict.value).then(rsp => {
if (rsp) {
query();
flag.modify = false;
}
})
}
onMounted(() => {
query();
});
</script>
<style lang="scss" scoped>
//@import url(); css
</style>

68
packages/manage/views/index.ts

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
import Login from './login.vue';
import Buffer from './buffer.vue';
import Config from './config.vue';
import Dictionary from './dictionary.vue';
import Permission from './permission.vue';
import Role from './role.vue';
import Status from './status.vue';
import Log from './log.vue';
const routes = [
{
path: '/login',
name: 'login',
component: Login,
},
{
path: '/buffer',
name: 'buffer',
component: Buffer,
},
{
path: '/config',
name: 'config',
component: Config,
},
{
path: '/dictionary',
name: 'dictionary',
component: Dictionary,
},
{
path: '/permission',
name: 'permission',
component: Permission,
},
{
path: '/role',
name: 'role',
component: Role,
},
{
path: '/status',
name: 'status',
component: Status,
},
{
path: '/log',
name: 'log',
component: Log,
},
];
const menus = {
buff: { i18n: 'preMenu.operator.0', path: 'buffer', icon: 'Warning' },
config: { i18n: 'preMenu.operator.1', path: 'config', icon: 'EditPen' },
dictionary: {
i18n: 'preMenu.operator.2',
path: 'dictionary',
icon: 'Collection',
},
permission: {
i18n: 'preMenu.operator.3',
path: 'permission',
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' },
};
export default { routes, menus };

43
packages/manage/views/log.vue

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
<template>
<SearchRow :title="t('log.title')" :add="false" :del="false" @query="query">
<NoobInput v-model="example.userId" :placeholder="t('log.prop.1')" />
<NoobDate v-model="example.startTime" :placeholder="t('log.start')" />
<NoobDate v-model="example.stopTime" :placeholder="t('log.stop')" />
</SearchRow>
<ListTable @query="query" :props="props" :example="example" :page="true" :data="result"></ListTable>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { Api, PageExample, PageResult, ListTable, SearchRow, NoobInput, NoobDate } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
const { list } = Api.log;
const result = ref(new PageResult());
const example = reactive<any>(new PageExample());
const props = [
{ i18n: 'log.prop.0', type: 'index', width: 80 },
{ i18n: 'log.prop.1', code: 'userId', width: 120 },
{ i18n: 'log.prop.2', code: 'module', width: 120, dict: 'log_module' },
{ i18n: 'log.prop.3', code: 'type', width: 150, dict: 'log_type' },
{ i18n: 'log.prop.4', code: 'time', width: 150 },
{ i18n: 'log.prop.5', code: 'loginIp', width: 180 },
{ i18n: 'log.prop.6', code: 'context', width: 300 }
]
const query = () => {
list(example).then((rsp: any) => result.value = rsp)
}
onMounted(() => {
dispatch('getDictMap', ['log_module', 'log_type'])
query();
});
</script>
<style lang="scss" scoped>
//@import url(); css
</style>

56
packages/manage/views/login.vue

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
<template>
<div class="login">
<LoginForm @login="login">
</LoginForm>
</div>
</template>
<script lang="ts" setup>
import { onBeforeMount, reactive, ref } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import md5 from "js-md5";
import { Api, LoginForm } from "noob-mengyxu";
const { state, commit } = useStore();
const router = useRouter();
onBeforeMount(() => {
state.size.headHeight = '0px';
state.size.asideWidth = '0px';
commit("initSize");
});
const login = user => {
const param = JSON.parse(JSON.stringify(user));
param.password = md5(param.password);
Api.pub.login(param).then(rsp => {
if (rsp) {
state.size.headHeight = state.size.head + 'px';
state.size.asideWidth = state.size.aside + 'px';
commit("initSize");
router.push('/')
}
})
};
</script>
<style lang='scss' scoped>
//@import url(); css
.login {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.canvas {
position: fixed;
z-index: -1; // background-color: black;
}
.logo {
width: 300px;
height: 90px;
}
</style>

136
packages/manage/views/permission.vue

@ -0,0 +1,136 @@ @@ -0,0 +1,136 @@
<template>
<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"
:treeProps="{ children: 'children' }">
<template #status="{ row }">
<div slot="reference" class="name-wrapper">
<NoobTag v-if="row.status == 'A'">
{{ t('base.active') }}
</NoobTag>
<NoobTag v-else type="danger">
{{ t('base.inactive') }}
</NoobTag>
</div>
</template>
<template #action="{ row }">
<TableAction :add="row.parent == null" @modify="modify(row)" @del="delate(row)" @add="addPermission(row)" />
</template>
</ListTable>
<el-dialog :title="t('base.add') + t('permission.name')" v-model="flag.modify" :close-on-click-modal="false" top="15vh"
width="40%" @keydown.enter.native="confirm">
<ModifyForm ref="form" :param="permission" :rules="rules" :items="items" @confirm="confirm" :width="100"
@cancel="flag.modify = false">
<template #id>
<NoobInput v-model="permission.id" full :placeholder="t('rule.pleaseEnter') + t('permission.prop.1')"
:disabled="!flag.add" />
</template>
<template #perOrder>
<NoobSelect v-model="permission.perOrder" full :max-value="99"
:placeholder="t('rule.pleaseSelect') + t('permission.prop.4')" />
</template>
</ModifyForm>
</el-dialog>
</template>
<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 { 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 example = reactive<any>(new PageExample());
const flag = reactive({
modify: false,
add: false
})
const permission = ref<any>();
const form = ref();
const order = 99;
const nodeLevel = {
module: 'group',
group: 'view',
view: 'action'
};
const props = [
{ i18n: 'permission.prop.0', code: 'name', width: 200, align: 'left', fixed: "left" },
{ i18n: 'permission.prop.1', code: 'id', width: 220 },
{ i18n: 'permission.prop.2', code: 'desc', slot: true, width: 80 },
{ i18n: 'permission.prop.3', code: 'perLevel', dict: 'per_level', width: 80 },
{ 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' },
]
const items = [
{ i18n: 'permission.prop.1', code: 'id', slot: true },
{ i18n: 'permission.parent', code: 'perParent', disabled: true },
{ i18n: 'permission.prop.3', code: 'perLevel', dict: 'per_level', disabled: true },
{ i18n: 'permission.prop.0', code: 'name' },
{ i18n: 'permission.prop.6', code: 'perContent' },
{ i18n: 'permission.prop.2', code: 'desc' },
{ i18n: 'permission.prop.4', code: 'perOrder', slot: true },
{ i18n: 'permission.prop.5', code: 'perStatus', dict: 'able_status' },
]
const rules = {
id: [new SimpleRequired('dict.prop.1')],
name: [new SimpleRequired('dict.prop.0')],
}
const query = () => {
list(example).then((rsp: any) => result.value = rsp)
}
const addPermission = (row) => {
permission.value = { perStatus: 'A' }
if (row) {
permission.value.perParent = row.id
permission.value.perLevel = nodeLevel[row.perLevel]
} else {
permission.value.perLevel = 'group';
}
form.value?.clearValidate();
flag.modify = true;
flag.add = true;
}
const modify = (row) => {
permission.value = JSON.parse(JSON.stringify(row));
form.value?.clearValidate();
flag.modify = true;
flag.add = false;
}
const delate = (row) => {
Element.confirm(t('dict.delete.0'), t('dict.delete.1')).then(() => {
del(row).then(query);
})
}
const confirm = () => {
const api = flag.add ? add : set;
api(permission.value).then(rsp => {
if (rsp) {
query();
flag.modify = false;
}
})
}
onMounted(() => {
dispatch('getDictMap', ['per_level', 'able_status'])
query();
});
</script>
<style lang="scss" scoped>
//@import url(); css
</style>

14
packages/manage/views/role.vue

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
<template>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
const { state, commit, dispatch } = useStore();
onMounted(() => {});
</script>
<style lang="scss" scoped>
//@import url(); css
</style>

14
packages/manage/views/status.vue

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
<template>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
const { state, commit, dispatch } = useStore();
onMounted(() => {});
</script>
<style lang="scss" scoped>
//@import url(); css
</style>

22
packages/tool/color.vue

@ -1,18 +1,19 @@ @@ -1,18 +1,19 @@
<template>
<h2>颜色对比器</h2>
<h2>{{ t('tool.colorCpar') }}</h2>
<div class="color-item" v-for="(item, i) in colors" :key="i">
<div>{{ state.lang.color + (i + 1) }}</div>
<SearchInput :width="120" v-model="colors[i]" />
<div>{{ t('base.color') + (i + 1) }}</div>
<NoobInput :width="120" v-model="colors[i]" />
<div :class="['color-view', 'c' + i]"></div>
</div>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref } from "vue";
import { SearchInput } from 'noob';
const { state, commit, dispatch } = useStore();
import { NoobInput } from 'noob-mengyxu';
import { useI18n } from "vue3-i18n";
import { useStore } from "vuex";
const { t } = useI18n();
const { state } = useStore();
const colors = reactive(new Array(10));
onMounted(() => { });
@ -56,16 +57,21 @@ onMounted(() => { }); @@ -56,16 +57,21 @@ onMounted(() => { });
&.c5 {
background-color: v-bind('"#" + colors[5]');
}
&.c6 {
background-color: v-bind('"#" + colors[6]');
}
&.c7 {
background-color: v-bind('"#" + colors[7]');
}
&.c8 {
background-color: v-bind('"#" + colors[8]');
}
&.c9 {
background-color: v-bind('"#" + colors[9]');
}
}</style>
}
</style>

8
packages/tool/terminal-split.vue

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
<template>
<el-row>
<el-col :span="12">
<div id="terminal" v-loading="flag.loading" ref="terminal" :element-loading-text="state.lang.connect"
<div id="terminal" v-loading="flag.loading" ref="terminal" :element-loading-text="t('tool.connect')"
@click.right.native="showClear($event)"></div>
</el-col>
<el-col :span="12">
<div id="response" v-loading="flag.loading" ref="response" :element-loading-text="state.lang.connect"></div>
<div id="response" v-loading="flag.loading" ref="response" :element-loading-text="t('tool.connect')"></div>
</el-col>
</el-row>
</template>
@ -14,6 +14,8 @@ import { ref, onMounted, onBeforeUnmount, watch, reactive } from "vue"; @@ -14,6 +14,8 @@ import { ref, onMounted, onBeforeUnmount, watch, reactive } from "vue";
import { useStore } from "vuex";
import { Terminal } from "xterm";
import "xterm/css/xterm.css";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state } = useStore();
const prop = defineProps({
url: {
@ -119,7 +121,7 @@ const onKey = e => { @@ -119,7 +121,7 @@ const onKey = e => {
}
}
const initTerm = () => {
const options = {
const options: any = {
lineHeight: 1.2,
fontSize: 16,
fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",

5
packages/tool/terminal.vue

@ -1,13 +1,14 @@ @@ -1,13 +1,14 @@
<template>
<div id="terminal" v-loading="flag.loading" ref="terminal" :element-loading-text="state.lang.connect"
<div id="terminal" v-loading="flag.loading" ref="terminal" :element-loading-text="t('tool.connect')"
@click.right.native="showClear($event)"></div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, watch, reactive } from "vue";
import { useStore } from "vuex";
import { Terminal } from "xterm";
import { useI18n } from "vue3-i18n";
import "xterm/css/xterm.css";
const { t } = useI18n();
const { state } = useStore();
const prop = defineProps({

66
plugs/api/buffer.ts

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

72
plugs/api/dictionary.ts

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
import { get, post, put, delate } from '../http/axios';
import { PageResult } from '../constant';
const pageResult = new PageResult();
const root = 'dict';
export const list = (example) => {
return new Promise((resolve, reject) => {
get(root, example).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(pageResult);
}
},
(err) => {
resolve(pageResult);
}
);
});
};
export const add = (dictionary) => {
return new Promise((resolve, reject) => {
post(root, dictionary).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const set = (dictionary) => {
return new Promise((resolve, reject) => {
put(root, dictionary).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const del = (dictionary) => {
return new Promise((resolve, reject) => {
delate(root, dictionary).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};

5
plugs/api/index.ts

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

20
plugs/api/log.ts

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
import { get } from '../http/axios';
import { PageResult } from '../constant';
const pageResult = new PageResult();
const root = 'log/action';
export const list = (example) => {
return new Promise((resolve, reject) => {
get(root, example).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(pageResult);
}
},
(err) => {
resolve(pageResult);
}
);
});
};

72
plugs/api/permission.ts

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
import { get, post, put, delate } from '../http/axios';
import { PageResult } from '../constant';
const pageResult = new PageResult();
const root = 'permission';
export const list = (example) => {
return new Promise((resolve, reject) => {
get(root, example).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(pageResult);
}
},
(err) => {
resolve(pageResult);
}
);
});
};
export const add = (dictionary) => {
return new Promise((resolve, reject) => {
post(root, dictionary).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const set = (dictionary) => {
return new Promise((resolve, reject) => {
put(root, dictionary).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const del = (dictionary) => {
return new Promise((resolve, reject) => {
delate(root, dictionary).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};

67
plugs/api/public.ts

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
import { get, post, put, delate } from '../http/axios';
const urls = {
dict: 'public/dict',
info: 'public/info',
login: 'public/login',
logout: 'public/logout',
};
export const getByCodes = (codes) => {
return new Promise((resolve, reject) => {
get(urls.dict, codes).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const getInfo = () => {
return new Promise((resolve, reject) => {
get(urls.info, null, true, true).then(
(rsp: any) => {
if (rsp) {
resolve(rsp);
} else {
resolve(false);
}
},
(err) => {
resolve(false);
}
);
});
};
export const login = (user) => {
return new Promise((resolve, reject) => {
post(urls.login, user).then(
(rsp: any) => {
resolve(rsp);
},
(err) => {
resolve(false);
}
);
});
};
export const logout = () => {
return new Promise((resolve, reject) => {
put(urls.logout).then(
(rsp: any) => {
resolve(rsp);
},
(err) => {
resolve(false);
}
);
});
};

5
plugs/config/index.ts

@ -1,3 +1,2 @@ @@ -1,3 +1,2 @@
export * as styles from './styles';
export * as size from './size';
export * as lang from './language';
export * as Styles from './styles';
export * as Size from './size';

32
plugs/config/language/chinese.ts

@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
export default class Chinese {
title = 'XXX管理系统';
language = '语言';
confirm = '确认';
cancel = '取消';
pleaseEnter = '请输入';
notBeNull = '这里不能为空';
pleaseSelect = '请选择';
changePwd = '修改密码';
pwd = '密码';
oldPwd = '旧密码';
newPwd = '新密码';
rePwd = '确认密码';
plsRePwd = '请再次输入新密码';
rePwdError = '两次输入密码不一致';
logout = '退出登录';
fullScreen = '切换全屏';
changeStyle = '切换主题';
default = '默认';
light = '明亮';
dark = '黑夜';
color = '颜色';
size = '尺寸';
normal = '正常';
small = '小';
large = '大';
connect = '拼命连接中';
}

31
plugs/config/language/english.ts

@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
export default class English {
title = 'XXX System';
language = 'Language';
confirm = 'Confirm';
cancel = 'Cancel';
pleaseEnter = 'Please enter ';
notBeNull = 'There cannot be empty';
pleaseSelect = 'Please select';
changePwd = 'Change password';
pwd = 'Password';
oldPwd = 'Old password';
newPwd = 'New password';
rePwd = 'Repeat password';
plsRePwd = 'Please enter the new password again';
rePwdError = 'The password is entered twice inconsistently';
logout = 'Logout';
fullScreen = 'Toggle full screen';
changeStyle = 'Switch themes';
default = 'Default';
light = 'Lignt';
dark = 'Dark';
color = 'Color';
size = 'Size';
normal = 'Normal';
small = 'Small';
large = 'Large';
connect = 'Desperately connected';
}

8
plugs/config/language/index.ts

@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
import Chinese from './chinese';
import English from './english';
const chinese = new Chinese();
const english = new English();
export { chinese, english };

7
plugs/config/size/index.ts

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
import Normal from './normal';
import Small from './small';
import Large from './large';
const normal = new Normal();
const small = new Small();
const large = new Large();
export { normal, small, large };
export const normal = new Normal();
export const small = new Small();
export const large = new Large();

23
plugs/config/size/large.ts

@ -1,16 +1,19 @@ @@ -1,16 +1,19 @@
export default class Small {
import Normal from './normal';
export default class Small extends Normal {
head = 60;
aside = 200;
size = 'large'; //总体尺寸
head: Number = 60;
aside: Number = 200;
fontSize = '18px';
titleSize = '20px';
headIconSize = '24px';
fontSize = '18px'; //总体字体尺寸
titleSize = '20px'; //标题字体尺寸
headIconSize = '24px'; //头部图标尺寸
headHeight = '60px'; //头部高度
headMenuWidth = '350px'; //头部右侧菜单宽度
asideWidth = '200px'; //左侧菜单宽度
mainPad = '8px';
menuIconSize = '20px';
searchRowHeight = '45px';
searchRowPad = '12px';
searchMargin = '15px';
searchRowHeight = '45px'; //查询行高
searchRowPad = '12px'; //查询行内间距
searchWidth = '190px'; //查询元素默认宽度
}

29
plugs/config/size/normal.ts

@ -1,16 +1,27 @@ @@ -1,16 +1,27 @@
export default class Normal {
head = 50;
aside = 180;
size = 'default'; //总体尺寸
head: Number = 50;
aside: Number = 180;
fontSize = '16px';
titleSize = '18px';
headIconSize = '20px';
fontSize = '16px'; //总体字体尺寸
titleSize = '18px'; //标题字体尺寸
headIconSize = '20px'; //头部图标尺寸
headHeight = '50px'; //头部高度
headMenuWidth = '300px'; //头部右侧菜单宽度
asideWidth = '180px'; //左侧菜单宽度
mainHeight = ''; //通用页面组件高度
mainPad = '5px'; //通用页面组件内边距
menuIconSize = '18px';
loginHeight = '350px';
loginWidth = '450px';
searchRowHeight = '40px'; //查询行高
searchRowPad = '10px'; //查询行内间距
searchMargin = '15px'; //查询元素水平间距
searchWidth = '170px'; //查询元素默认宽度
searchRowHeight = '40px';
searchRowPad = '10px';
searchMargin = '15px';
tableHeight = 0; //表格默认高度
pTableHeight = 0; //带分页表格默认高度
pageHeight = 36; //分页插件高度
}

25
plugs/config/size/small.ts

@ -1,16 +1,21 @@ @@ -1,16 +1,21 @@
export default class Small {
import Normal from './normal';
export default class Small extends Normal {
head = 45;
aside = 160;
size = 'small'; //总体尺寸
head: Number = 45;
aside: Number = 160;
fontSize = '14px';
titleSize = '16px';
headIconSize = '16px';
fontSize = '14px'; //总体字体尺寸
titleSize = '16px'; //标题字体尺寸
headIconSize = '16px'; //头部图标尺寸
headHeight = '45px'; //头部高度
headMenuWidth = '250px'; //头部右侧菜单宽度
asideWidth = '160px'; //左侧菜单宽度
searchRowHeight = '35px';
searchRowPad = '7px';
searchMargin = '10px';
menuIconSize = '16px';
searchRowHeight = '35px'; //表格查询行高
searchRowPad = '7px'; //查询行内间距
searchMargin = '10px'; //查询元素水平间距
searchWidth = '150px'; //查询元素默认宽度
pageHeight = 28; //分页插件高度
}

6
plugs/config/styles/dark.ts

@ -1,7 +1,8 @@ @@ -1,7 +1,8 @@
import NoobStyle from './noob';
import Plain from './plain';
import { light, dark, grey } from './color';
export default class Dark extends NoobStyle {
export default class Dark extends Plain {
name = 'dark'; //总体样式名称
bodyBg = dark[3]; //全局背景颜色
titleColor = light[0]; //标题颜色
color = grey[5]; //全局字体颜色
@ -22,4 +23,5 @@ export default class Dark extends NoobStyle { @@ -22,4 +23,5 @@ export default class Dark extends NoobStyle {
tableCurBg = dark[5]; //当前行背景颜色
tableColor = light[0]; //表格字体颜色
tableBorderColor = dark[7]; //行底部边框颜色
tableChildBg = dark[3]; //树型表格子行背景颜色
}

9
plugs/config/styles/index.ts

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
import NoobStyle from './noob';
import Plain from './plain';
import Light from './light';
import Dark from './dark';
const noobStyle = new NoobStyle();
const light = new Light();
const dark = new Dark();
export { noobStyle, light, dark };
export const plain = new Plain();
export const light = new Light();
export const dark = new Dark();

11
plugs/config/styles/light.ts

@ -1,7 +1,8 @@ @@ -1,7 +1,8 @@
import NoobStyle from './noob';
import Plain from './plain';
import { light, dark, grey } from './color';
export default class Light extends NoobStyle {
export default class Light extends Plain {
name = 'light'; //总体样式名称
bodyBg = light[0]; //全局背景颜色
titleColor = dark[0]; //标题颜色
@ -13,4 +14,10 @@ export default class Light extends NoobStyle { @@ -13,4 +14,10 @@ export default class Light extends NoobStyle {
searchRowBg = light[0];
itemBg = light[1];
tableBg = light[0]; //表格背景颜色
tableHeadBg = light[0]; //表头行背景颜色
tableCurBg = light[2]; //当前行背景颜色
tableColor = dark[0]; //表格字体颜色
tableBorderColor = light[9]; //行底部边框颜色
}

11
plugs/config/styles/noob.ts → plugs/config/styles/plain.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import { light, dark } from './color';
export default class NoobStyle {
size = 'small'; //总体尺寸
export default class Plain {
name = 'plain'; //总体样式名称
// bodyBg = light[0]; //全局背景颜色
bodyBg = light[7]; //全局背景颜色
titleColor = light[0]; //标题颜色
@ -22,9 +22,10 @@ export default class NoobStyle { @@ -22,9 +22,10 @@ export default class NoobStyle {
itemBg = light[2];
itemSelectColor = '#409eff';
tableBg = light[0]; //表格背景颜色
tableHeadBg = light[0]; //表头行背景颜色
tableCurBg = light[0]; //当前行背景颜色
tableBg = light[1]; //表格背景颜色
tableHeadBg = light[2]; //表头行背景颜色
tableCurBg = light[3]; //当前行背景颜色
tableColor = dark[0]; //表格字体颜色
tableBorderColor = light[9]; //行底部边框颜色
tableChildBg = '#f0f9eb'; //树型表格子行背景颜色
}

8
plugs/constant.ts

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
export class PageResult {
data = [];
total = 0;
}
export class PageExample {
page = 1;
size = 20;
}

29
plugs/element/formatter.ts

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
import { useStore } from 'vuex';
const { state } = useStore();
export const getValue = (
row: any,
column: string,
value: any,
index?: number
) => {
if ((value == null || value == '') && value !== 0) {
return '--';
}
return value;
};
export const formatter = (row: any, column: any, value: any, index: number) => {
return formatterByDist(row.scheme + '-' + column.property, value);
};
export const formatterByDist = (dictKey, value) => {
if (!dictKey) {
return getValue(null, '', value);
}
const mapping = state.dict[dictKey];
if (mapping == null) {
return getValue(null, '', value);
}
return mapping[value] == null ? value : mapping[value];
};

31
plugs/element/message.ts

@ -8,12 +8,13 @@ import { @@ -8,12 +8,13 @@ import {
let curMsg;
let count = 0;
let instance;
import { i18n } from '../i18n';
const t = i18n.t;
export function loading() {
if (count === 0) {
instance = ElLoading.service({
lock: true,
text: '加载中...',
text: t('base.loading'),
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.3)',
});
@ -30,7 +31,7 @@ export function close() { @@ -30,7 +31,7 @@ export function close() {
}
}
export function showMessage(type, info, unClose) {
export function showMessage(type, info, unClose?) {
if (curMsg != null) {
curMsg.close();
}
@ -74,8 +75,8 @@ export function success(msg) { @@ -74,8 +75,8 @@ export function success(msg) {
export const confirm = (msg: string, title: string) => {
return new Promise((resolve, reject) => {
ElMessageBox.confirm(msg, title, {
confirmButtonText: '确定',
cancelButtonText: '取消',
confirmButtonText: t('base.confirm'),
cancelButtonText: t('base.cancel'),
buttonSize: 'default',
confirmButtonClass: 'el-button--info',
type: 'warning',
@ -84,3 +85,23 @@ export const confirm = (msg: string, title: string) => { @@ -84,3 +85,23 @@ export const confirm = (msg: string, title: string) => {
.catch(reject);
});
};
export const prompt = (
msg: string,
title: string,
pattern: RegExp,
errorMsg: string
) => {
return new Promise((resolve, reject) => {
ElMessageBox.confirm(msg, title, {
confirmButtonText: t('base.confirm'),
cancelButtonText: t('base.cancel'),
buttonSize: 'default',
confirmButtonClass: 'el-button--info',
inputPattern: pattern,
inputErrorMessage: errorMsg,
})
.then(resolve)
.catch(reject);
});
};

142
plugs/element/rule.ts

@ -1,97 +1,89 @@ @@ -1,97 +1,89 @@
let lang;
export const setLang = (language) => (lang = language);
import { i18n } from '../i18n';
const t = i18n.t;
export class SimpleRequired {
required = true;
message: string;
trigger = 'blur';
constructor(name?: string) {
if (name) {
this.message = lang.pleaseEnter + name;
} else {
this.message = lang.notBeNull;
name?: string;
selection?: boolean;
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');
callback(new Error(msg));
}
callback();
};
constructor(name?: string, selection?: boolean) {
this.name = name;
this.selection = selection;
selection && (this.trigger = 'change');
}
}
export class SimpleCharacter {
required: boolean;
message: string;
max?: number;
max: number;
min?: number;
trigger: string = 'blur';
constructor(name?: string, max?: number, required?: boolean) {
if (required == null || required == undefined) {
this.required = true;
} else {
this.required = required;
}
if (!max) {
max = 255;
}
this.max = max;
if (name) {
if (this.required) {
this.message = '请输入不超过' + max + '字符的' + name;
} else {
this.message = name + '最长不超过' + max + '字符';
}
} else {
this.message = lang.notBeNull;
validator = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback();
} else if (value.length > this.max) {
callback(new Error(t('rule.maxLen', [this.max])));
} else if (this.min && value.length < this.min) {
callback(new Error(t('rule.minLen', [this.min])));
}
callback();
};
constructor(max?: number, min?: number) {
this.max = max || 255;
this.min = min;
}
}
export class Character {
pattern: RegExp;
message: string = '输入格式不正确';
trigger = 'blur';
validator = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback();
} else if (!this.pattern.test(value)) {
callback(new Error(t('rule.formatErr')));
}
callback();
};
constructor(pattern: RegExp) {
this.pattern = pattern;
}
}
export class SimpleSelection {
required: boolean;
message: string;
trigger: string;
constructor(name?: string) {
this.required = true;
this.trigger = 'change';
if (name) {
this.message = lang.pleaseSelect + name;
} else {
this.message = lang.notBeNull;
}
}
}
export class SimpleNumber {
trigger: string = 'blur';
min?: Number;
max?: Number;
min?: number;
max?: number;
validator = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback();
}
if (!new RegExp(/^(0|-?[1-9]\d*)$/).test(value)) {
callback(new Error('请输入整数'));
const msg = t('rule.pleaseEnter') + t('rule.int').toLowerCase();
callback(new Error(msg));
}
const num = parseInt(value);
if (rule.min != null && num < rule.min) {
callback(new Error('最小值为' + rule.min));
callback(new Error(t('rule.min', [this.min])));
}
if (rule.max != null && num > rule.max) {
callback(new Error('最大值为' + rule.max));
if (this.max != null && num > this.max) {
callback(new Error(t('rule.max', [this.max])));
}
callback();
};
constructor(min?: number, max?: Number) {
constructor(min?: number, max?: number) {
this.min = min;
this.max = max;
}
@ -108,11 +100,11 @@ export class Hexadecimal { @@ -108,11 +100,11 @@ export class Hexadecimal {
value.trim().length == 0 ||
!new RegExp(/^[0-9a-fA-F\s]+$/).test(value)
) {
callback(new Error('请输入十六进制数字'));
} else if (rule.min != null && value.length < rule.min) {
callback(new Error('请输入至少' + rule.min + '位'));
} else if (rule.max != null && value.length > rule.max) {
callback(new Error('请输入最多' + rule.max + '位'));
callback(new Error(t('rule.hexadecimal')));
} else if (this.min != null && value.length < this.min) {
callback(new Error(t('rule.minLen', [this.min])));
} else if (this.max != null && value.length > this.max) {
callback(new Error(t('rule.maxLen', [this.max])));
} else {
callback();
}
@ -134,11 +126,7 @@ export class Longitude extends Character { @@ -134,11 +126,7 @@ export class Longitude extends Character {
}
export class Latitude 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-8]\d?))(\.\d{1,10})?|90(\.0{1,10})?)$/));
}
}
@ -220,11 +208,11 @@ export class IdCard { @@ -220,11 +208,11 @@ export class IdCard {
91: '国外',
};
if (!/^\d{17}(\d|x)$/i.test(value)) {
callback(new Error('你输入的身份证长度或格式错误'));
callback(t('rule.idCard.format'));
}
value = value.replace(/x$/i, 'a');
if (aCity[parseInt(value.substr(0, 2))] == null) {
callback(new Error('你的身份证地区非法'));
callback(new Error(t('rule.idCard.area')));
}
const sBirthday =
@ -238,13 +226,13 @@ export class IdCard { @@ -238,13 +226,13 @@ export class IdCard {
sBirthday !=
d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()
) {
callback(new Error('身份证上的出生日期非法'));
callback(new Error(t('rule.idCard.birth')));
}
for (let i = 17; i >= 0; i--) {
iSum += (Math.pow(2, i) % 11) * parseInt(value.charAt(17 - i), 11);
}
if (iSum % 11 != 1) {
callback(new Error('你输入的身份证号非法'));
callback(new Error(t('rule.idCard.error')));
}
}
callback();
@ -258,11 +246,11 @@ export class SimplePassword { @@ -258,11 +246,11 @@ export class SimplePassword {
max?: Number = 16;
validator = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback(new Error(lang.pleaseEnter + lang.pwd.toLowerCase()));
callback(new Error(t('rule.pleaseEnter') + t('pwd.pwd').toLowerCase()));
} else if (value.length < 6 || value.length > 18) {
callback(new Error('密码长度为:6~18位'));
callback(new Error(t('pwd.length', [6, 18])));
} else if (!new RegExp('^[^ ]+$').test(value)) {
callback(new Error('密码不能包含空格'));
callback(new Error(t('pwd.noSpace')));
}
callback();
};
@ -275,15 +263,15 @@ export class Password { @@ -275,15 +263,15 @@ export class Password {
max?: Number = 16;
validator = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback(new Error('请输入密码'));
callback(new Error(t('rule.pleaseEnter') + t('pwd.pwd').toLowerCase()));
} else if (value.length < 8 || value.length > 20) {
callback(new Error('密码长度为:8~20位'));
callback(new Error(t('pwd.length', [8, 20])));
} else if (
!new RegExp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).*$').test(value)
) {
callback(new Error('密码至少包含大小写字母和数字'));
callback(new Error(t('pwd.required')));
} else if (!new RegExp('^[^ ]+$').test(value)) {
callback(new Error('密码不能包含空格'));
callback(new Error(t('pwd.noSpace')));
}
callback();
};

20
plugs/axios.ts → plugs/http/axios.ts

@ -1,6 +1,8 @@ @@ -1,6 +1,8 @@
/* eslint-disable */
import axios from 'axios';
import { loading, close, showMessage } from './element';
import { loading, close, showMessage } from '../element';
import { i18n } from '../i18n';
const t = i18n.t;
const config = {
baseURL: process.env.VUE_APP_BASE_URL ? '/api' : '',
@ -14,8 +16,6 @@ _axios.defaults.headers.put['Content-Type'] = 'application/json;charset=UTF-8'; @@ -14,8 +16,6 @@ _axios.defaults.headers.put['Content-Type'] = 'application/json;charset=UTF-8';
_axios.defaults.headers.delete['Content-Type'] =
'application/json;charset=UTF-8';
let curMsg: any;
let logout;
export const registerLogout = (method) => {
@ -149,7 +149,7 @@ function handResponse(response, resolve, noMsg, noLoading) { @@ -149,7 +149,7 @@ function handResponse(response, resolve, noMsg, noLoading) {
if (response.success) {
if (response.message) {
if (!noMsg) {
showMessage('success', response.message, false);
showMessage('success', response.message);
}
resolve(true);
} else if (response.data) {
@ -162,13 +162,13 @@ function handResponse(response, resolve, noMsg, noLoading) { @@ -162,13 +162,13 @@ function handResponse(response, resolve, noMsg, noLoading) {
logout();
}
if (response.message == 'no permission') {
response.message = '您暂无权访问,请联系管理员添加';
response.message = t('http.unPermission');
}
if (response.message?.indexOf('no permission for ') == 0) {
response.message = '此权限尚未开放,请勿越权访问';
response.message = t('http.noPermission');
}
if (!noMsg) {
showMessage('error', response.message, false);
showMessage('error', response.message);
}
response.error && console.log(response.error);
resolve(false);
@ -180,7 +180,7 @@ function handError(err, reject, noMsg, noLoading) { @@ -180,7 +180,7 @@ function handError(err, reject, noMsg, noLoading) {
close();
}
if (!noMsg) {
showMessage('error', '网络错误', false);
showMessage('error', t('http.error'));
}
reject(err);
}
@ -226,7 +226,7 @@ export function download(fileName, url, data = {}, callBack?) { @@ -226,7 +226,7 @@ export function download(fileName, url, data = {}, callBack?) {
try {
const result = JSON.parse(reader.result);
if (typeof result === 'object') {
showMessage('error', result.message, false);
showMessage('error', result.message);
if (callBack != null) {
callBack(false);
}
@ -253,7 +253,7 @@ export function download(fileName, url, data = {}, callBack?) { @@ -253,7 +253,7 @@ export function download(fileName, url, data = {}, callBack?) {
},
(err) => {
close();
showMessage('error', '下载失败,网络异常!', false);
showMessage('error', t('http.downFail'));
if (callBack != null) {
callBack(false);
}

226
plugs/http/axios2.ts

@ -0,0 +1,226 @@ @@ -0,0 +1,226 @@
/* eslint-disable */
import axios from 'axios';
import { loading, close, showMessage } from '../element';
import { i18n } from '../i18n';
const t = i18n.t;
const config = {
baseURL: process.env.VUE_APP_BASE_URL ? '/api' : '',
timeout: 60 * 1000,
withCredentials: true, // Check cross-site Access-Control
};
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';
export const registerBaseUrl = (url) => {
_axios.defaults.baseURL = url;
};
// Add a request interceptor
_axios.interceptors.request.use(
function (config) {
const time = new Date().getTime().toString();
const params = config.params;
if (params) {
delEmpty(params);
params.t = time;
}
const data = config.data;
if (data != null && typeof data === 'object') {
delEmpty(data);
data.t = time;
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
function delEmpty(data) {
if (data) {
for (const item in data) {
if (data.hasOwnProperty(item)) {
const val = data[item];
if ((val == null || val == 'null' || val == '') && val !== 0) {
delete data[item];
}
}
}
}
}
// Add a response interceptor
_axios.interceptors.response.use(
function (response) {
return response.data;
},
function (error) {
return Promise.reject(error);
}
);
export function post(url, data?, noMsg?, noLoading?) {
return new Promise((resolve, reject) => {
if (!noLoading) {
loading();
}
_axios.post(url, data).then(
(response: any) => {
handResponse(response, resolve, noMsg, noLoading);
},
(err) => {
handError(err, reject, noMsg, noLoading);
}
);
});
}
export function get(url, data?, noMsg?, noLoading?) {
return new Promise((resolve, reject) => {
if (!noLoading) {
loading();
}
_axios.get(url, { params: data }).then(
(response: any) => {
handResponse(response, resolve, noMsg, noLoading);
},
(err) => {
handError(err, reject, noMsg, noLoading);
}
);
});
}
export function put(url, data?, noMsg?, noLoading?) {
return new Promise((resolve, reject) => {
if (!noLoading) {
loading();
}
_axios.put(url, data).then(
(response: any) => {
handResponse(response, resolve, noMsg, noLoading);
},
(err) => {
handError(err, reject, noMsg, noLoading);
}
);
});
}
export function delate(url, data?, noMsg?, noLoading?) {
return new Promise((resolve, reject) => {
if (!noLoading) {
loading();
}
_axios({
method: 'delete',
url: url,
data: data,
}).then(
(response: any) => {
handResponse(response, resolve, noMsg, noLoading);
},
(err) => {
handError(err, reject, noMsg, noLoading);
}
);
});
}
function handResponse(response, resolve, noMsg, noLoading) {
if (!noLoading) {
close();
}
resolve(response);
}
function handError(err, reject, noMsg, noLoading) {
if (!noLoading) {
close();
}
if (!noMsg) {
showMessage('error', t('http.error'), false);
}
reject(err);
}
export function upload(file, url, data) {
return new Promise((resolve, reject) => {
let param = new FormData(); // 创建form对象
param.append('file', file); // 通过append向form对象添加数据
if (data) {
for (const item in data) {
if (data.hasOwnProperty(item)) {
param.append(item, data[item]); // 添加form表单中其他数据
}
}
}
let config = {
headers: { 'Content-Type': 'multipart/form-data' },
};
_axios.post(url, param, config).then(
(response) => {
handResponse(response, resolve, false, false);
},
(err) => {
handError(err, reject, false, false);
}
);
});
}
export function download(fileName, url, data = {}, callBack?) {
loading();
_axios({
method: 'get',
url: url, // 请求地址
params: data, // 参数
responseType: 'blob', // 表明返回服务器返回的数据类型
}).then(
(response: any) => {
close();
const reader = new FileReader() as any;
reader.readAsText(response);
reader.onload = function () {
try {
const result = JSON.parse(reader.result);
if (typeof result === 'object') {
showMessage('error', result.message, false);
if (callBack != null) {
callBack(false);
}
return;
}
} catch (err) {}
const blob = new Blob([response], {
type: 'application/octet-stream',
});
const navigator = window.navigator as any;
if (navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, fileName);
} else {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
window.URL.revokeObjectURL(link.href);
}
if (callBack != null) {
callBack(true);
}
};
},
(err) => {
close();
showMessage('error', t('http.downFail'));
if (callBack != null) {
callBack(false);
}
}
);
}

2
plugs/http/index.ts

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
export * as Axios from './axios';
export * as Axios2 from './axios2';

150
plugs/i18n/en.ts

@ -0,0 +1,150 @@ @@ -0,0 +1,150 @@
export default class English {
title = 'XXX SYSTEM';
base = {
color: 'Color',
add: 'Add',
delete: 'Delete',
modify: 'Modify',
stop: 'Stop',
select: 'Select',
confirm: 'Confirm',
cancel: 'Cancel',
loading: 'Loading...',
active: 'Active',
inactive: 'Inactive',
key: 'Key',
value: 'Value',
};
pwd = {
login: 'login',
userId: 'User name',
changePwd: 'Change password',
pwd: 'Password',
oldPwd: 'Old password',
newPwd: 'New password',
rePwd: 'Repeat password',
plsRePwd: 'Please enter the new password again',
rePwdError: 'The password is entered twice inconsistently',
length: 'The password length is: {0}~{1} characters',
noSpace: 'The password cannot contain spaces',
required:
'The password contains at least uppercase and lowercase letters and numbers',
};
head = {
center: 'Personal center',
logout: 'Logout',
fullScreen: 'Toggle full screen',
changeStyle: 'Switch themes',
default: 'Default',
light: 'Lignt',
dark: 'Dark',
language: 'Language',
zh: 'Chinese',
en: 'English',
size: 'Size',
normal: 'Normal',
small: 'Small',
large: 'Large',
};
tool = {
colorCpar: 'Color Comparator',
connect: 'Desperately connected',
};
rule = {
pleaseEnter: 'Please enter ',
notNull: 'There cannot be empty',
pleaseSelect: 'Please select',
formatErr: 'The input format is incorrect',
int: 'Number',
max: 'The max value is {0}',
min: 'The min value is {0}',
maxLen: 'Enter up to {0} character',
minLen: 'Enter a minimum of {0} character',
hexadecimal: 'Please enter hexadecimal digits',
idCard: {
format: 'The ID card is wrong in length or format',
area: 'The ID area is illegal',
birth: 'The date of birth on the ID card is illegal',
error: 'The ID number is illegal',
},
};
http = {
unPermission:
'You do not have access yet, please contact your administrator to add it',
noPermission:
'This permission is not yet open, do not access without permission',
error: 'Network error',
downFail: 'Download failed with network abnormality!',
};
preMenu = {
operator: [
'Buffer',
'Config',
'Dictionary',
'Permission',
'Role',
'Status',
'Log',
],
};
log = {
title: 'Action log list',
prop: [
'Sequence',
'Action user',
'Log module',
'Action type',
'Action time',
'Login IP',
'Log content',
],
start: 'Start time',
stop: 'Stop time',
};
dict = {
title: 'Dictionary manage',
name: ' type/dictionary',
prop: ['Name', 'Code', 'Description', 'Status', 'Action'],
example: ['Type name(Fuzzy queries)', 'Type code', 'Status'],
delete: [
'Confirm whether to delete the dictionary/dictionary type (deleting a dictionary type deletes all dictionaries under that type)?',
'Tips',
],
};
permission = {
title: 'Permission manage',
name: 'permission',
parent: 'Permission parent',
prop: [
'Name',
'Code',
'Icon',
'Level',
'Priority',
'Status',
'Content',
'Action',
],
example: ['Permission code'],
delete: ['Are you sure you want to remove the permission?', 'Tips'],
};
buffer = {
title: '缓存管理',
clean: '清空失效缓存',
modify: '修改有效期',
prop: ['缓存值', '唯一键', '是否有效', '失效时间', '操作'],
delete: ['确定要删除此条缓存吗?', '提示'],
delay: ['请输入失效时间(yyyy-MM-dd HH:mm:ss)', '修改'],
};
}

17
plugs/i18n/index.ts

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
import { createI18n } from 'vue3-i18n';
import Zh from './zh';
import En from './en';
const messages = {
zh: new Zh(),
en: new En(),
};
const i18n = createI18n({
locale: 'zh',
messages,
});
const registerLang = (name, data) => {
messages[name] = data;
};
export { i18n, Zh, En, registerLang };

147
plugs/i18n/zh.ts

@ -0,0 +1,147 @@ @@ -0,0 +1,147 @@
export default class Zh {
title = 'XXX管理系统';
base = {
color: '颜色',
add: '添加',
delete: '删除',
modify: '修改',
stop: '停止',
select: '查询',
confirm: '确认',
cancel: '取消',
loading: '加载中...',
active: '生效',
inactive: '无效',
key: '键',
value: '值',
};
pwd = {
login: '登 录',
changePwd: '修改密码',
userId: '用户名',
pwd: '密码',
oldPwd: '旧密码',
newPwd: '新密码',
rePwd: '确认密码',
plsRePwd: '请再次输入新密码',
rePwdError: '两次输入密码不一致',
length: '密码长度为:{0}~{1}位',
noSpace: '密码不能包含空格',
required: '密码至少包含大小写字母和数字',
};
head = {
center: '个人中心',
logout: '退出登录',
fullScreen: '切换全屏',
changeStyle: '切换主题',
default: '默认',
light: '明亮',
dark: '黑夜',
language: '语言',
zh: '中文',
en: '英文',
size: '尺寸',
normal: '正常',
small: '小',
large: '大',
};
tool = {
colorCpar: '颜色对比器',
connect: '拼命连接中',
};
rule = {
pleaseEnter: '请输入',
notNull: '这里不能为空',
pleaseSelect: '请选择',
formatErr: '输入格式不正确',
int: '整数',
max: '最大值为{0}',
min: '最小值为{0}',
maxLen: '最多输入{0}个字符',
minLen: '最少输入{0}个字符',
hexadecimal: '请输入十六进制数字',
idCard: {
format: '你输入的身份证长度或格式错误',
area: '你输入的身份证地区非法',
birth: '你输入的身份证出生日期非法',
error: '你输入的身份证号非法',
},
};
http = {
unPermission: '您暂无权访问,请联系管理员添加',
noPermission: '此权限尚未开放,请勿越权访问',
error: '网络错误',
downFail: '下载失败,网络异常!',
};
preMenu = {
operator: [
'缓存管理',
'系统配置',
'数据字典',
'权限管理',
'角色管理',
'状态管理',
'接口日志',
],
};
log = {
title: '接口日志查询',
prop: [
'序号',
'操作用户',
'日志模块',
'操作类型',
'操作时间',
'登录IP',
'日志信息',
],
start: '开始时间',
stop: '结束时间',
};
dict = {
title: '数据字典管理',
name: '类型/字典',
prop: ['字典名称', '字典编码', '字典说明', '字典状态', '操作'],
example: ['字典类型名称(模糊查询)', '字典类型编码', '状态'],
delete: [
'确认是否删除该字典/字典类型(删除字典类型将删除该类型下所有字典)?',
'提示',
],
};
permission = {
title: '权限管理',
name: '权限',
parent: '父权限',
prop: [
'权限名称',
'权限编号',
'菜单图标',
'权限级别',
'排序优先级',
'权限状态',
'权限内容',
'操作',
],
example: ['权限编号'],
delete: ['确定要删除该权限吗?', '提示'],
};
buffer = {
title: '缓存管理',
clean: '清空失效缓存',
modify: '修改有效期',
prop: ['缓存值', '唯一键', '是否有效', '失效时间', '操作'],
delete: ['确定要删除此条缓存吗?', '提示'],
delay: ['请输入失效时间(yyyy-MM-dd HH:mm:ss)', '修改'],
};
}

9
plugs/index.ts

@ -1,4 +1,7 @@ @@ -1,4 +1,7 @@
export * from './element';
export * from './store';
export * from './axios';
export * from './config';
export * as Element from './element';
export * as Store from './store';
export * as Http from './http';
export * as Lang from './i18n';
export * as Api from './api';
export * from './constant';

94
plugs/store/index.ts

@ -1,21 +1,89 @@ @@ -1,21 +1,89 @@
import { createStore as create } from 'vuex';
import { styles, lang, size } from '../config';
import { setLang } from '../element';
import { Styles, Size } from '../config';
import { getByCodes, getInfo } from '../api/public';
const state = {
style: styles.noobStyle,
lang: lang.chinese,
size: size.small,
export class State {
dict = {
active_status: {
A: '启用',
B: '禁用',
},
test: {
a: 'A',
b: 'B',
c: 'C',
},
};
setLang(lang.chinese);
style = Styles.plain;
size = Size.normal;
}
const mutations = {
updateState(state, param) {
state[param.prop] = param.value;
},
export class Actions {
getDictMap = ({ state, commit }, codes) => {
if (codes == null) {
return;
}
const arr: Array<any> = [];
for (let i = 0; i < codes.length; i++) {
const code = codes[i];
state.dict[code] || arr.push(code);
}
if (arr.length == 0) {
return;
}
getByCodes({ codes: arr.join() }).then((rsp: any) => {
if (rsp) {
for (let i = 0; i < arr.length; i++) {
const key = arr[i];
const dict = {};
if (rsp[key]) {
rsp[key].forEach((item) => {
dict[item.code] = item.name;
});
}
commit('updateDict', [key, dict]);
}
}
});
};
}
export class Mutations {
updateState = (state, param) => {
state[param[0]] = param[1];
};
initSize = (state, height) => {
const size = state.size;
const head = parseInt(size.headHeight);
const mainPad = parseInt(size.mainPad);
const searchRow = parseInt(size.searchRowHeight);
const searchRowPad = parseInt(size.searchRowPad);
if (height) {
size.height = height;
} else {
height = size.height;
}
size.mainHeight = Math.floor(height - head) + 'px';
size.tableHeight =
height - 2 * (mainPad + searchRowPad) - 3 - searchRow - head;
size.pTableHeight = size.tableHeight - size.pageHeight;
};
updateDict = (state, param) => {
state.dict[param[0]] = param[1];
};
}
export interface StoreOptions {
state?: State;
getters?;
actions?;
mutations?: Mutations;
modules?;
plugins?;
strict?: boolean;
devtools?: boolean;
}
export const createStore = (options) => {
Object.assign(options.state, state);
Object.assign(options.mutations, mutations);
return create(options);
};

7
tsconfig.json

@ -21,11 +21,8 @@ @@ -21,11 +21,8 @@
"@/": [
"./"
],
"noob": [
"./packages"
],
"plugs": [
"./plugs"
"noob-mengyxu": [
"./index.ts"
]
},
"lib": [

19
vue.config.js

@ -4,6 +4,20 @@ const { config } = require('process'); @@ -4,6 +4,20 @@ const { config } = require('process');
const resolve = (dir) => path.join(__dirname, dir);
module.exports = {
transpileDependencies: true,
devServer: {
proxy: {
'/api': {
target: process.env.VUE_APP_BASE_URL,
// 允许跨域
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': '',
},
},
},
},
pages: {
index: {
entry: 'examples/main.ts', // 入口文件
@ -16,14 +30,13 @@ module.exports = { @@ -16,14 +30,13 @@ module.exports = {
config.module
.rule('js')
.include.add(resolve('packages'))
.add(resolve('plugs'))
.end()
.use('babel') // 编译器
.loader('babel-loader')
.tap((option) => {
return option;
});
config.resolve.alias
.set('noob', resolve('packages'))
.set('plugs', resolve('plugs'));
config.resolve.alias.set('noob-mengyxu', resolve('./index.ts'));
},
};

30
yarn.lock

@ -276,9 +276,9 @@ @@ -276,9 +276,9 @@
js-tokens "^4.0.0"
"@babel/parser@^7.20.15", "@babel/parser@^7.21.3":
version "7.22.7"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae"
integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==
version "7.22.16"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95"
integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==
"@babel/parser@^7.20.7", "@babel/parser@^7.21.4":
version "7.21.4"
@ -2824,10 +2824,10 @@ electron-to-chromium@^1.4.284: @@ -2824,10 +2824,10 @@ electron-to-chromium@^1.4.284:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.356.tgz#b75a8a8c31d571f6024310cc980a08cd6c15a8c5"
integrity sha512-nEftV1dRX3omlxAj42FwqRZT0i4xd2dIg39sog/CnCJeCcL1TRd2Uh0i9Oebgv8Ou0vzTPw++xc+Z20jzS2B6A==
element-plus@2.2.18:
version "2.2.18"
resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-2.2.18.tgz#62b388e05587506d2d40bede0729046f7c41f9d9"
integrity sha512-2pK2zmVOwP14eFl3rGoR+3BWJwDyO+DZCvzjQ8L6qjUR+hVKwFhgxIcSkKJatbcHFw5Xui6UyN20jV+gQP7mLg==
element-plus@2.2.20:
version "2.2.20"
resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-2.2.20.tgz#f4395c276c0945cc8dbb8e6ed4a8d97f173a1ca2"
integrity sha512-ludShd3f5kNRY4FLzeoNitLcwZ4qs2M/zwKeyeE7rUzZJAQ0BZtcT3SvZoEoBLmgxw9jHoonl4WIwon4UzhyRA==
dependencies:
"@ctrl/tinycolor" "^3.4.1"
"@element-plus/icons-vue" "^2.0.6"
@ -3654,6 +3654,11 @@ joi@^17.4.0: @@ -3654,6 +3654,11 @@ joi@^17.4.0:
"@sideway/formula" "^3.0.1"
"@sideway/pinpoint" "^2.0.0"
js-md5@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/js-md5/-/js-md5-0.7.3.tgz#b4f2fbb0b327455f598d6727e38ec272cd09c3f2"
integrity sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==
js-message@1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47"
@ -3872,9 +3877,9 @@ lru-cache@^6.0.0: @@ -3872,9 +3877,9 @@ lru-cache@^6.0.0:
yallist "^4.0.0"
magic-string@^0.30.0:
version "0.30.1"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.1.tgz#ce5cd4b0a81a5d032bd69aab4522299b2166284d"
integrity sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==
version "0.30.3"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.3.tgz#403755dfd9d6b398dfa40635d52e96c5ac095b85"
integrity sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.15"
@ -5599,6 +5604,11 @@ vue-template-es2015-compiler@^1.9.0: @@ -5599,6 +5604,11 @@ vue-template-es2015-compiler@^1.9.0:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
vue3-i18n@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/vue3-i18n/-/vue3-i18n-1.1.5.tgz#e00839e05b176bb2527f00fcd1bcdd82e1416fa9"
integrity sha512-DN5XfE0z6BnFxjbP/qW8AKI5QCex97L2l8z7G76ccTkfTsJ18n4mXGCy4K9H2rm4FlzDx/USPlPqQK64yXQqDg==
vue@^3.2.25:
version "3.3.4"
resolved "https://registry.yarnpkg.com/vue/-/vue-3.3.4.tgz#8ed945d3873667df1d0fcf3b2463ada028f88bd6"

Loading…
Cancel
Save