Browse Source

feat: add new components and helper methods

dev
hechang27-sprt 6 months ago
parent
commit
9bfa5cc76c
  1. 102
      packages/base/data/listTableDialog.vue
  2. 44
      packages/base/index.ts
  3. 46
      packages/base/item/buttonWithTooltip.vue
  4. 22
      packages/base/item/confirmCancel.vue
  5. 112
      packages/base/item/datetime.vue
  6. 54
      packages/base/item/tzDatePicker.vue
  7. 55
      packages/base/item/tzDateTime.vue
  8. 130
      packages/echarts/line/smoothed.vue
  9. 364
      packages/manage/router/index.vue
  10. 339
      packages/manage/router/zhuBeiDong.vue
  11. 11
      packages/manage/views/scope.vue
  12. 6
      plugs/composables/index.ts
  13. 32
      plugs/composables/useActionPers.ts
  14. 86
      plugs/composables/useListTable.ts
  15. 18
      plugs/composables/useLoading.ts
  16. 132
      plugs/composables/useModifyForm.ts
  17. 43
      plugs/composables/useSysDict.ts
  18. 12
      plugs/composables/useWatchOnce.ts
  19. 68
      plugs/element/listTableDialog.ts
  20. 318
      plugs/http/axios3.ts
  21. 6
      plugs/http/index.ts
  22. 10
      plugs/http/misc.ts
  23. 17
      plugs/index.ts
  24. 2
      plugs/store/index.ts
  25. 21
      plugs/util/asyncUtil.ts
  26. 22
      plugs/util/objectUtil.ts

102
packages/base/data/listTableDialog.vue

@ -0,0 +1,102 @@ @@ -0,0 +1,102 @@
<template>
<el-container>
<el-main>
<ListTable
page
border
:data="tableData.rows"
:props="propsWithSelection"
:row-key="rowKey"
:example="tableData.example"
@query="tableData.query()"
>
<template v-for="{ code } in propsWithSlot" #[code]="{ row }">
<slot :name="code" :row />
</template>
<template #ui_selection="{ row }">
<el-checkbox
:value="selection.get(row[rowKey])"
@update:model-value="
(val) => {
if (val) {
selection.set(row[rowKey], row);
} else {
selection.delete(row[rowKey]);
}
}
"
/>
</template>
</ListTable>
</el-main>
<el-footer>
<ConfirmCancel @confirm="handleConfirm" @cancel="handleCancel" />
</el-footer>
</el-container>
</template>
<script setup lang="ts">
import { ListTable, Element, AsyncHandler, useAsyncEmits, useListTable, useSysDict, ConfirmCancel } from "noob-mengyxu";
import { computed, onMounted, reactive, ref } from "vue";
import { useStore } from "vuex";
import { useI18n } from "vue3-i18n";
import { ListTableProps } from "../../../plugs/element/listTableDialog";
import { PageResponse } from "../../../plugs/http";
const { showMessage } = Element;
const { t } = useI18n();
defineOptions({ inheritAttrs: false });
type Row = Record<string, any>;
const p = defineProps<ListTableProps>();
type Emits = {
query: [handler: AsyncHandler<PageResponse<Row>>, example: Record<string, any>];
confirm: [handler: AsyncHandler<void>, rows: Row[]];
close: [handler: AsyncHandler<void>];
};
const emits = defineEmits<Emits>();
const emitsAsync = useAsyncEmits<Emits>(emits);
const propsWithSelection = computed(() => [
{ code: "ui_selection", slot: true, i18n: "common.select", width: 80 },
...p.props,
]);
const propsWithSlot = computed(() => p.props.filter((col) => col.slot));
const store = useStore();
const { sysDict, updateDict } = useSysDict();
const tableData = useListTable({
query: (example) => emitsAsync("query", example),
initialPage: p.initialPage,
initialPageSize: p.initialPageSize,
initExample: p.initExample,
disableAutoQuery: true,
});
const selection = reactive(new Map());
const handleConfirm = async () => {
try {
await emitsAsync("confirm", Array.from(selection.values()));
await emitsAsync("close");
} catch {
showMessage("error", t("common.errors.submitError"));
}
};
const handleCancel = async () => {
await emitsAsync("close");
};
onMounted(async () => {
if (p.useDicts) {
await updateDict(p.useDicts);
}
await tableData.query();
});
</script>

44
packages/base/index.ts

@ -1,16 +1,32 @@ @@ -1,16 +1,32 @@
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';
import LightBox from './item/light-box.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";
import LightBox from "./item/light-box.vue";
import ButtonWithTooltip from "./item/buttonWithTooltip.vue";
import ConfirmCancel from "./item/confirmCancel.vue";
import TzDatePicker from "./item/tzDatePicker.vue";
import TzDateTime from "./item/tzDateTime.vue";
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 Descriptions from "./data/descriptions.vue";
import TableAction from "./data/table-action.vue";
import ListTableDialog from "./data/listTableDialog.vue";
export { NoobTag, NoobButton, NoobSelect, NoobInput, NoobDate, LightBox };
export {
NoobTag,
NoobButton,
NoobSelect,
NoobInput,
NoobDate,
LightBox,
ButtonWithTooltip,
TzDateTime,
TzDatePicker,
ConfirmCancel,
};
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 Descriptions from './data/descriptions.vue';
import TableAction from './data/table-action.vue';
export { SearchRow, ListTable, Infomation, ModifyForm, Descriptions, TableAction };
export { SearchRow, ListTable, ListTableDialog, Infomation, ModifyForm, Descriptions, TableAction };

46
packages/base/item/buttonWithTooltip.vue

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
<template>
<el-tooltip
v-if="props.tooltip"
:content="props.tooltip"
:disabled="props.disabled"
:show-after="0"
:hide-after="0"
:popper-options="{ modifiers: [{ name: 'eventListeners', enabled: false }] }"
popper-class="non-interactive-tooltip"
>
<NoobButton :disabled="props.disabled" v-bind="buttonProps">
<slot />
</NoobButton>
</el-tooltip>
<NoobButton v-else :disabled="props.disabled" v-bind="buttonProps">
<slot />
</NoobButton>
</template>
<script setup lang="ts">
import { useAttrs } from "vue";
import { ElTooltip } from "element-plus";
import { computed } from "vue";
import { NoobButton } from "noob-mengyxu";
defineOptions({ inheritAttrs: false });
interface Props {
tooltip?: string;
disabled: boolean;
}
const props = defineProps<Props>();
const attrs = useAttrs();
const buttonProps = computed(() => {
const { class: _, ...rest } = attrs;
return rest;
});
</script>
<style>
.non-interactive-tooltip {
pointer-events: none !important;
}
</style>

22
packages/base/item/confirmCancel.vue

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
<template>
<el-row>
<NoobButton type="primary" @click="emit('confirm')">{{
t("base.confirm")
}}</NoobButton>
<el-space fill />
<NoobButton type="info" @click="emit('cancel')">{{
t("base.cancel")
}}</NoobButton>
</el-row>
</template>
<script setup lang="ts">
import { NoobButton } from "noob-mengyxu";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const emit = defineEmits<{
(e: "confirm"): void | Promise<void>;
(e: "cancel"): void | Promise<void>;
}>();
</script>

112
packages/base/item/datetime.vue

@ -1,73 +1,87 @@ @@ -1,73 +1,87 @@
<template>
<el-date-picker :size="state.size.size" :class="['form-item', full && 'full']" :value-format="formater"
v-model="myValue" :type="type" :placeholder="placeholder || t('rule.pleaseEnter')" :disabled="disabled"
:clearable="clearable" :teleported="false" />
<el-date-picker
:size="state.size.size"
:class="['form-item', full && 'full']"
:value-format="formater"
v-model="myValue"
:type="type"
: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';
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: 'datetime'
},
disabled: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: true,
},
full: {
type: Boolean,
default: false,
},
formater: {
type: String,
default: 'YYYY-MM-DD HH:mm:ss'
},
width: {
type: Number
}
modelValue: null,
placeholder: {
type: String,
default: null,
},
type: {
type: String,
default: "datetime",
},
disabled: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: true,
},
full: {
type: Boolean,
default: false,
},
formater: {
type: String,
default: "YYYY-MM-DD HH:mm:ss",
},
width: {
type: Number,
},
});
const emit = defineEmits(["update:modelValue"]);
const myValue = ref(null);
const width = ref('150px');
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) => {
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) => {
emit("update:modelValue", n);
});
watch(
() => prop.modelValue,
(n, o) => {
myValue.value = n;
})
}
);
onMounted(() => {
prop.modelValue && (myValue.value = prop.modelValue);
setWidth();
prop.modelValue && (myValue.value = prop.modelValue);
setWidth();
});
</script>
<style lang="scss">
//@import url(); css
.form-item {
width: v-bind('width');
width: v-bind("width");
}
</style>
</style>

54
packages/base/item/tzDatePicker.vue

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
<template>
<el-date-picker v-model="model"> </el-date-picker>
</template>
<script setup lang="ts">
import { ElDatePicker } from "element-plus";
import dayjs, { type Dayjs } from "dayjs";
import { nextTick, toRef, watch, watchEffect } from "vue";
import { watchEffectOnce } from "../../../plugs/composables";
interface Props {
valueType: "iso8601" | "unix" | "unixMillis";
tz?: string;
keepMillis?: boolean;
}
const props = defineProps<Props>();
watchEffectOnce(toRef(props, "tz"), async () => {
const timeZone = await import("dayjs/plugin/timezone");
dayjs.extend(timeZone.default);
});
const model = defineModel<string | number, string, Date, Date>({
get: (value) => {
let dt: Dayjs;
if (props.valueType === "unix" || props.valueType === "unixMillis") {
if (typeof value === "string") {
value = parseFloat(value);
}
dt = props.valueType === "unix" ? dayjs.unix(value) : dayjs(value);
} else {
dt = dayjs(value);
}
return dt.toDate();
},
set: (value) => {
const dt = dayjs(value);
if (props.valueType === "unix") {
return dt.unix();
} else if (props.valueType === "unixMillis") {
return dt.valueOf();
} else if (props.valueType === "iso8601" && props.tz) {
const fmt = props.keepMillis ? "YYYY-MM-DDTHH:mm:ss.SSSZ" : "YYYY-MM-DDTHH:mm:ssZ";
return dt.tz(props.tz).format(fmt);
} else {
const isoWithMillis = dt.toISOString();
if (props.keepMillis) return isoWithMillis;
else return isoWithMillis.slice(0, 19).concat("Z");
}
},
});
</script>

55
packages/base/item/tzDateTime.vue

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
<template>
{{ display }}
</template>
<script setup lang="ts">
import dayjs from "dayjs";
import { computed, toRef } from "vue";
import { watchEffectOnce } from "noob-mengyxu";
interface Props {
value: string | number;
valueFormat?: string;
valueTz?: string;
displayFormat?: string;
locale?: string;
type?: "iso8601" | "unix" | "unixMillis";
}
const props = defineProps<Props>();
watchEffectOnce(toRef(props, "valueFormat"), async () => {
const customParseFormat = await import("dayjs/plugin/customParseFormat");
dayjs.extend(customParseFormat.default);
});
watchEffectOnce(toRef(props, "valueTz"), async () => {
const timeZone = await import("dayjs/plugin/timezone");
dayjs.extend(timeZone.default);
});
const parsed = computed(() => {
if (props.type === "unix" || props.type === "unixMillis") {
const value = typeof props.value === "string" ? parseFloat(props.value) : props.value;
return props.type === "unix" ? dayjs.unix(value) : dayjs(value);
} else {
if (props.valueFormat && props.valueTz) {
return dayjs.tz(props.value, props.valueFormat, props.valueTz);
} else if (props.valueTz) {
return dayjs.tz(props.value, props.valueTz);
} else if (props.valueFormat) {
return dayjs(props.value, props.valueFormat);
} else {
return dayjs(props.value);
}
}
});
const display = computed(() => {
let dt = parsed.value;
if (props.locale) {
dt = dt.locale(props.locale);
}
return dt.format(props.displayFormat);
});
</script>

130
packages/echarts/line/smoothed.vue

@ -2,78 +2,84 @@ @@ -2,78 +2,84 @@
<script lang="ts" setup>
import { useStore } from "vuex";
import { get, post, put, delate } from "@/config/axios";
import { reactive, onMounted, ref } from "vue";
const { state, commit, dispatch } = useStore();
const prop = defineProps({
title: {
type: String,
default: 'Smoothed Line'
},
name: {
type: String
},
xAxis: {
type: Array,
default: []
},
data: {
type: Array,
default: []
},
markLine: {
type: String
},
unit: {
type: String
}
})
title: {
type: String,
default: "Smoothed Line",
},
name: {
type: String,
},
xAxis: {
type: Array,
default: [],
},
data: {
type: Array,
default: [],
},
markLine: {
type: String,
},
unit: {
type: String,
},
});
const options = {
title: {
text: "",//
left: "center"
},
tooltip: {
trigger: "axis",
formatter: '{b}' + '<br>' +
'<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:#5470c6"></span>'
+ '<span style="float:right;margin-left:10px;font-size:14px;color:#666;font-weight:900"/>' + '{c}' + '次'
},
xAxis: {
type: "category",
data: []
},
yAxis: {
type: "value"
},
series: [
{
data: [],
type: "line",
smooth: true,
markLine: {
symbol: 'none', //['none']线['arrow', 'none']线['none','arrow']线
label: {
position: "end" //start,"middle","end"
},
data: [{
silent: false, // truefalse
lineStyle: { //线
type: "solid", // solid'dotted'
color: "#FA3934"
},
yAxis: 22 // 线yAxis,线 {type : 'average', name: ''}type max min average
}]
}
title: {
text: "", //
left: "center",
},
tooltip: {
trigger: "axis",
formatter:
"{b}" +
"<br>" +
'<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:#5470c6"></span>' +
'<span style="float:right;margin-left:10px;font-size:14px;color:#666;font-weight:900"/>' +
"{c}" +
"次",
},
xAxis: {
type: "category",
data: [],
},
yAxis: {
type: "value",
},
series: [
{
data: [],
type: "line",
smooth: true,
markLine: {
symbol: "none", //['none']线['arrow', 'none']线['none','arrow']线
label: {
position: "end", //start,"middle","end"
},
],
data: [
{
silent: false, // truefalse
lineStyle: {
//线
type: "solid", // solid'dotted'
color: "#FA3934",
},
yAxis: 22, // 线yAxis,线 {type : 'average', name: ''}type max min average
},
],
},
},
],
};
onMounted(() => { });
onMounted(() => {});
</script>
<style lang="scss" scoped>
//@import url(); css
</style>
</style>

364
packages/manage/router/index.vue

@ -1,247 +1,241 @@ @@ -1,247 +1,241 @@
<template>
<el-container :style="appMain" ref="main" v-show="!flag.loading">
<el-header v-show="state.size.headHeight != '0px'" class="app-head" :height="state.size.headHeight">
<Head :title="title" :logo="logo" :username="username">
<template #left>
<MenuTree v-show="mode == 'horizontal'" :data="menus" mode="horizontal" />
</template>
<HeadPersonal @updatePwd="updatePwd" @logout="onLogout" :center="center" />
<Fullscreen />
<StyleChange v-if="styleAble" />
<LangChange v-if="langAble" />
<SizeChange v-if="sizeAble" />
</Head>
</el-header>
<el-container id="container">
<el-aside v-show="mode == 'vertical' && state.size.asideWidth != '0px'" :width="state.size.asideWidth">
<MenuTree :data="menus" mode="vertical" />
</el-aside>
<el-main class="app-main">
<router-view />
</el-main>
</el-container>
<el-container :style="appMain" ref="main" v-show="!flag.loading">
<el-header v-show="state.size.headHeight != '0px'" class="app-head" :height="state.size.headHeight">
<Head :title="title" :logo="logo" :username="username">
<template #left>
<MenuTree v-show="mode == 'horizontal'" :data="menus" mode="horizontal" />
</template>
<HeadPersonal @updatePwd="updatePwd" @logout="onLogout" :center="center" />
<Fullscreen />
<StyleChange v-if="styleAble" />
<LangChange v-if="langAble" />
<SizeChange v-if="sizeAble" />
</Head>
</el-header>
<el-container id="container">
<el-aside v-show="mode == 'vertical' && state.size.asideWidth != '0px'" :width="state.size.asideWidth">
<MenuTree :data="menus" mode="vertical" />
</el-aside>
<el-main class="app-main">
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script lang="ts" setup>
import { reactive, onMounted, ref, onBeforeUnmount } from "vue";
import { onBeforeUnmount, onMounted, reactive, ref } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { NoobHead, Api } from "noob-mengyxu"
const { Head, MenuTree, HeadPersonal, Fullscreen, StyleChange, LangChange, SizeChange } = NoobHead;
import { Api, NoobHead } from "noob-mengyxu";
import md5 from "js-md5";
const { Head, MenuTree, HeadPersonal, Fullscreen, StyleChange, LangChange, SizeChange } = NoobHead;
const { state, commit, dispatch } = useStore();
const emit = defineEmits(['updatePwd', 'logout']);
const router = useRouter()
const emit = defineEmits(["updatePwd", "logout"]);
const router = useRouter();
const appMain = reactive({
height: window.innerHeight + 'px',
backgroundColor: state.style.bodyBg
height: window.innerHeight + "px",
backgroundColor: state.style.bodyBg,
});
const main = ref();
const flag = reactive({
showHeader: true,
showAside: true,
loading: false
})
showHeader: true,
showAside: true,
loading: false,
});
let interval = 0;
const props = defineProps({
title: {
type: String,
default: null,
},
menus: {
type: Array<any>(),
default: null
},
mode: {
type: String,
default: 'vertical',
},
styleAble: {
type: Boolean,
default: true,
},
sizeAble: {
type: Boolean,
default: true,
},
langAble: {
type: Boolean,
default: true,
},
center: {
type: String,
default: 'home',
},
checkUser: {
type: Boolean,
default: true,
},
username: {
type: String,
default: null,
},
closeAble: {
type: Boolean,
default: false,
},
logo: {
type: String,
default: null,
},
title: {
type: String,
default: null,
},
menus: {
type: Array<any>(),
default: null,
},
mode: {
type: String,
default: "vertical",
},
styleAble: {
type: Boolean,
default: true,
},
sizeAble: {
type: Boolean,
default: true,
},
langAble: {
type: Boolean,
default: true,
},
center: {
type: String,
default: "home",
},
checkUser: {
type: Boolean,
default: true,
},
username: {
type: String,
default: null,
},
closeAble: {
type: Boolean,
default: false,
},
logo: {
type: String,
default: null,
},
});
const onResize = () => {
const height = window.innerHeight;
appMain.height = height + 'px';
commit('initSize', [height, window.innerWidth]);
}
const height = window.innerHeight;
appMain.height = height + "px";
commit("initSize", [height, window.innerWidth]);
};
const getUser = (first?) => {
if (!props.checkUser) {
return;
if (!props.checkUser) {
return;
}
first && (flag.loading = true);
Api.pub.getInfo().then((rsp) => {
first && (flag.loading = false);
if (rsp) {
if (state.user?.userId !== rsp.userId) {
commit("updateState", ["user", rsp]);
}
} else {
router.push("/login");
}
first && (flag.loading = true);
Api.pub.getInfo().then((rsp) => {
first && (flag.loading = false);
if (rsp) {
if (state.user?.userId !== rsp.userId) {
commit('updateState', ['user', rsp]);
}
} else {
router.push('/login');
}
});
});
};
const onLogout = () => {
Api.pub.logout().then(rsp => {
getUser();
});
}
Api.pub.logout().then((rsp) => {
getUser();
});
};
const updatePwd = pwd => {
pwd.old = md5(pwd.old);
pwd.new = md5(pwd.new);
pwd.reNew = md5(pwd.reNew);
emit('updatePwd', pwd);
Api.user.updatePwd(pwd);
}
const updatePwd = (pwd) => {
pwd.old = md5(pwd.old);
pwd.new = md5(pwd.new);
pwd.reNew = md5(pwd.reNew);
emit("updatePwd", pwd);
Api.user.updatePwd(pwd);
};
onMounted(() => {
router.push("/")
dispatch("getMenus");
getUser(true);
interval = setInterval(getUser, 5000);
window.onresize = onResize;
onResize();
router.push("/");
dispatch("getMenus");
getUser(true);
interval = setInterval(getUser, 5000);
window.onresize = onResize;
onResize();
});
onBeforeUnmount(() => {
clearInterval(interval);
})
clearInterval(interval);
});
</script>
<style lang='scss'>
@charset "UTF-8";
<style lang="scss">
body {
font-size: v-bind('state.size.fontSize') !important;
font-family: "Microsoft YaHei";
width: 100%;
height: 100%;
overflow: hidden;
padding: 0px;
margin: 0px;
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: 0px 0px 0px 3px !important;
padding: 0 !important;
height: v-bind('state.size.mainHeight');
box-shadow: 2px 2px 5px 3px #e5e6eb;
border-radius: 4px;
margin: 0px 0px 0px 3px !important;
padding: 0 !important;
height: v-bind("state.size.mainHeight");
}
.el-header,
.main-head,
.main-table {
padding: 0;
padding: 0;
}
#app,
#container,
.app-main {
background-color: v-bind('state.style.bodyBg');
color: v-bind('state.style.color');
font-size: v-bind('state.size.fontSize');
background-color: v-bind("state.style.bodyBg");
color: v-bind("state.style.color");
font-size: v-bind("state.size.fontSize");
}
.app-head {
padding: 0px !important;
background-color: v-bind('state.style.headBg');
height: v-bind('state.size.headHeight');
padding: 0px !important;
background-color: v-bind("state.style.headBg");
height: v-bind("state.size.headHeight");
}
.head-icon {
float: right;
cursor: pointer;
height: v-bind('state.size.headHeight');
margin-right: 20px;
font-size: v-bind('state.size.headIconSize');
align-items: center;
color: v-bind('state.style.color');
float: right;
cursor: pointer;
height: v-bind("state.size.headHeight");
margin-right: 20px;
font-size: v-bind("state.size.headIconSize");
align-items: center;
color: v-bind("state.style.color");
}
.form-item {
margin-right: v-bind('state.size.searchMargin');
margin-right: v-bind("state.size.searchMargin");
&.full {
width: 100%;
margin-right: 0px;
}
&.full {
width: 100%;
margin-right: 0px;
}
}
#app {
.el-input,
.el-textarea,
.el-date-editor,
.el-input__wrapper {
--el-input-bg-color: v-bind('state.style.itemBg') !important;
--el-fill-color-blank: 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-drawer {
--el-drawer-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;
--el-disabled-bg-color: v-bind('state.style.itemBg') !important;
}
*::selection {
background-color: v-bind('state.style.selectionBg');
color: v-bind('state.style.selectionColor');
}
.el-input,
.el-textarea,
.el-date-editor,
.el-input__wrapper {
--el-input-bg-color: v-bind("state.style.itemBg") !important;
--el-fill-color-blank: 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-drawer {
--el-drawer-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;
--el-disabled-bg-color: v-bind("state.style.itemBg") !important;
}
*::selection {
background-color: v-bind("state.style.selectionBg");
color: v-bind("state.style.selectionColor");
}
}
</style>
</style>

339
packages/manage/router/zhuBeiDong.vue

@ -1,239 +1,234 @@ @@ -1,239 +1,234 @@
<template>
<el-container :style="appMain" ref="main" v-show="!flag.loading">
<el-aside :width="state.size.asideWidth">
<MenuTree :title="title || t('title')" :logo="logo" :data="menus" mode="vertical" />
</el-aside>
<el-container id="container">
<el-header v-show="state.size.headHeight != '0px'" class="app-head" :height="state.size.headHeight">
<Head :title="title" :logo="logo" :username="username" :closeAble="true">
<template #left>
<MenuTree v-show="state.size.asideWidth == '0px'" :data="menus" mode="horizontal" />
</template>
<HeadPersonal @updatePwd="updatePwd" @logout="onLogout" :center="center" />
<Fullscreen />
<LangChange v-if="langAble" />
<SizeChange v-if="sizeAble" />
<slot></slot>
</Head>
</el-header>
<el-main class="app-main">
<router-view />
</el-main>
</el-container>
<el-container :style="appMain" ref="main" v-show="!flag.loading">
<el-aside :width="state.size.asideWidth">
<MenuTree :title="title || t('title')" :logo="logo" :data="menus" mode="vertical" />
</el-aside>
<el-container id="container">
<el-header v-show="state.size.headHeight != '0px'" class="app-head" :height="state.size.headHeight">
<Head :title="title" :logo="logo" :username="username" :closeAble="true">
<template #left>
<MenuTree v-show="state.size.asideWidth == '0px'" :data="menus" mode="horizontal" />
</template>
<HeadPersonal @updatePwd="updatePwd" @logout="onLogout" :center="center" />
<Fullscreen />
<LangChange v-if="langAble" />
<SizeChange v-if="sizeAble" />
<slot></slot>
</Head>
</el-header>
<el-main class="app-main">
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script lang="ts" setup>
import { reactive, onMounted, ref, onBeforeUnmount } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { NoobHead, Api, Styles, Size } from "noob-mengyxu"
import { NoobHead, Api, Styles, Size } from "noob-mengyxu";
const { Head, MenuTree, HeadPersonal, Fullscreen, StyleChange, LangChange, SizeChange } = NoobHead;
import md5 from "js-md5";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
const emit = defineEmits(['updatePwd', 'logout']);
const router = useRouter()
const emit = defineEmits(["updatePwd", "logout"]);
const router = useRouter();
const appMain = reactive({
height: window.innerHeight + 'px',
backgroundColor: state.style.bodyBg
height: window.innerHeight + "px",
backgroundColor: state.style.bodyBg,
});
const main = ref();
const flag = reactive({
showHeader: true,
showAside: true,
loading: false
})
showHeader: true,
showAside: true,
loading: false,
});
let interval = 0;
state.style = Styles.light;
const props = defineProps({
title: {
type: String,
default: null,
},
menus: {
type: Array<any>(),
default: null
},
styleAble: {
type: Boolean,
default: true,
},
sizeAble: {
type: Boolean,
default: true,
},
langAble: {
type: Boolean,
default: true,
},
center: {
type: String,
default: 'home',
},
checkUser: {
type: Boolean,
default: true,
},
username: {
type: String,
default: null,
},
logo: {
type: String,
default: null,
},
title: {
type: String,
default: null,
},
menus: {
type: Array<any>(),
default: null,
},
styleAble: {
type: Boolean,
default: true,
},
sizeAble: {
type: Boolean,
default: true,
},
langAble: {
type: Boolean,
default: true,
},
center: {
type: String,
default: "home",
},
checkUser: {
type: Boolean,
default: true,
},
username: {
type: String,
default: null,
},
logo: {
type: String,
default: null,
},
});
const onResize = () => {
const height = window.innerHeight;
appMain.height = height + 'px';
commit('initSize', [height, window.innerWidth]);
}
const height = window.innerHeight;
appMain.height = height + "px";
commit("initSize", [height, window.innerWidth]);
};
const getUser = (first?) => {
if (!props.checkUser) {
return;
if (!props.checkUser) {
return;
}
first && (flag.loading = true);
Api.pub.getInfo().then((rsp) => {
first && (flag.loading = false);
if (rsp) {
commit("updateState", ["user", rsp]);
} else {
router.push("/login");
}
first && (flag.loading = true);
Api.pub.getInfo().then((rsp) => {
first && (flag.loading = false);
if (rsp) {
commit('updateState', ['user', rsp]);
} else {
router.push('/login');
}
});
});
};
const onLogout = () => {
Api.pub.logout().then(rsp => {
getUser();
});
}
Api.pub.logout().then((rsp) => {
getUser();
});
};
const updatePwd = pwd => {
pwd.old = md5(pwd.old);
pwd.new = md5(pwd.new);
pwd.reNew = md5(pwd.reNew);
emit('updatePwd', pwd);
Api.user.updatePwd(pwd);
}
const updatePwd = (pwd) => {
pwd.old = md5(pwd.old);
pwd.new = md5(pwd.new);
pwd.reNew = md5(pwd.reNew);
emit("updatePwd", pwd);
Api.user.updatePwd(pwd);
};
onMounted(() => {
router.push("/")
dispatch("getMenus");
getUser(true);
interval = setInterval(getUser, 5000);
window.onresize = onResize;
onResize();
commit('updateState', ['style', Styles.plain]);
router.push("/");
dispatch("getMenus");
getUser(true);
interval = setInterval(getUser, 5000);
window.onresize = onResize;
onResize();
commit("updateState", ["style", Styles.plain]);
});
onBeforeUnmount(() => {
clearInterval(interval);
})
clearInterval(interval);
});
</script>
<style lang='scss'>
@charset "UTF-8";
<style lang="scss">
body {
font-size: v-bind('state.size.fontSize') !important;
font-family: "Microsoft YaHei";
width: 100%;
height: 100%;
overflow: hidden;
padding: 0px;
margin: 0px;
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: 0px 0px 0px 3px !important;
padding: 0 !important;
height: v-bind('state.size.mainHeight');
box-shadow: 2px 2px 5px 3px #e5e6eb;
border-radius: 4px;
margin: 0px 0px 0px 3px !important;
padding: 0 !important;
height: v-bind("state.size.mainHeight");
}
.el-header,
.main-head,
.main-table {
padding: 0;
padding: 0;
}
#app,
#container,
.app-main {
background-color: v-bind('state.style.bodyBg');
color: v-bind('state.style.color');
font-size: v-bind('state.size.fontSize');
background-color: v-bind("state.style.bodyBg");
color: v-bind("state.style.color");
font-size: v-bind("state.size.fontSize");
}
.app-head {
padding: 0px !important;
background-color: v-bind('state.style.headBg');
height: v-bind('state.size.headHeight');
padding: 0px !important;
background-color: v-bind("state.style.headBg");
height: v-bind("state.size.headHeight");
}
.head-icon {
float: right;
cursor: pointer;
height: v-bind('state.size.headHeight') !important;
margin-right: 20px !important;
font-size: v-bind('state.size.headIconSize') !important;
align-items: center !important;
color: v-bind('state.style.color') !important;
float: right;
cursor: pointer;
height: v-bind("state.size.headHeight") !important;
margin-right: 20px !important;
font-size: v-bind("state.size.headIconSize") !important;
align-items: center !important;
color: v-bind("state.style.color") !important;
}
.form-item {
margin-right: v-bind('state.size.searchMargin');
margin-right: v-bind("state.size.searchMargin");
&.full {
width: 100%;
margin-right: 0px;
}
&.full {
width: 100%;
margin-right: 0px;
}
}
#app {
.el-input,
.el-textarea,
.el-date-editor,
.el-input__wrapper {
--el-input-bg-color: v-bind('state.style.itemBg') !important;
--el-fill-color-blank: 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-drawer {
--el-drawer-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;
--el-disabled-bg-color: v-bind('state.style.itemBg') !important;
}
*::selection {
background-color: v-bind('state.style.selectionBg');
color: v-bind('state.style.selectionColor');
}
.el-input,
.el-textarea,
.el-date-editor,
.el-input__wrapper {
--el-input-bg-color: v-bind("state.style.itemBg") !important;
--el-fill-color-blank: 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-drawer {
--el-drawer-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;
--el-disabled-bg-color: v-bind("state.style.itemBg") !important;
}
*::selection {
background-color: v-bind("state.style.selectionBg");
color: v-bind("state.style.selectionColor");
}
}
</style>
</style>

11
packages/manage/views/scope.vue

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped lang="scss">
</style>

6
plugs/composables/index.ts

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
export * from "./useActionPers";
export * from "./useListTable";
export * from "./useLoading";
export * from "./useModifyForm";
export * from "./useSysDict";
export * from "./useWatchOnce";

32
plugs/composables/useActionPers.ts

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
import { onMounted, toRef } from "vue";
import { useRoute } from "vue-router";
import { useStore } from "vuex";
export function useActionPers(parent?: string) {
const store = useStore();
if (!parent) {
const route = useRoute();
parent = route.path;
}
const update = async () => {
await store.dispatch("updateActionPers", parent);
};
const actionPers = toRef(() => {
// @ts-ignore
const pers = store.state.actionPers[parent] ?? [];
return Object.fromEntries(pers.map((code) => [code, true]));
});
onMounted(async () => {
await update();
});
return {
get: (per) => !!actionPers.value[per],
update,
actionPers,
};
}

86
plugs/composables/useListTable.ts

@ -0,0 +1,86 @@ @@ -0,0 +1,86 @@
import { toReactive } from "@vueuse/core";
import { reactive, ref, shallowRef, watchEffect } from "vue";
import * as Element from "../element";
import { useI18n } from "vue3-i18n";
import { PageResponse } from "../http";
const { showMessage } = Element;
export interface TableColumn {
code: string;
name?: string;
i18n?: string;
width: number;
dict?: string;
slot?: boolean;
[others: string]: any;
}
export interface TableData {
rows: PageResponse<any>;
example: Record<string, any>;
}
interface Options {
query: (example: any) => Promise<PageResponse<any> | Record<string, any>[] | undefined>;
initialPage?: number;
initialPageSize?: number;
initExample?: Record<string, any>;
disableAutoQuery?: boolean;
deep?: boolean;
}
export function useListTable(options: Options) {
const { t } = useI18n();
const { initialPage, initialPageSize, initExample, deep } = options;
type Row = Record<string, any>;
type Rows = Row[] | PageResponse<Row>;
const empty = <T>() => [] as T[];
const rows = deep ? ref<Rows>(empty()) : shallowRef<Rows>(empty());
const setRows = (resp?: Rows) => {
if (resp == null) {
rows.value = empty();
} else {
rows.value = resp;
if (Array.isArray(resp) || resp.total == null) {
for (const key in pageParams) {
delete example[key];
}
}
}
};
const pageParams = {
page: initialPage || 1,
size: initialPageSize || 10,
};
const example = reactive<any>({
...pageParams,
...initExample,
});
const query = async () => {
try {
const resp = await options.query(example);
setRows(resp);
} catch (error) {
showMessage("error", t("common.errors.listTableQueryError"));
}
};
if (!options.disableAutoQuery) {
watchEffect(query);
}
return {
rows: toReactive(rows),
example,
setRows,
query,
};
}

18
plugs/composables/useLoading.ts

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
// composables/useLoading.js
import { ElLoading } from 'element-plus'
export function useLoading() {
const showLoading = (options = {}) => {
return ElLoading.service({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.3)',
...options
})
}
return {
showLoading
}
}

132
plugs/composables/useModifyForm.ts

@ -0,0 +1,132 @@ @@ -0,0 +1,132 @@
import { reactive, Ref } from "vue";
import {} from "noob-mengyxu";
import * as Element from "../element";
import { clearAndAssign, deepCopy } from "../util/objectUtil";
const { showMessage } = Element;
export interface FormProp {
code: string;
name?: string;
i18n?: string;
dict?: string;
slot?: boolean;
[others: string]: any;
}
interface Options {
props?: FormProp[];
formRef?: Ref<any>;
handleAdd?: (value) => Promise<void>;
handleEdit?: (value) => Promise<void>;
handleCancel?: () => Promise<void>;
handleError?: (kind: "validation" | "internal", err?) => void;
init?: any;
extraProps?: string[] | "any" | ((code: string) => boolean);
}
export function useModifyForm(options: Options) {
const { formRef, handleAdd, handleEdit, handleCancel, init, extraProps } = options;
const initValue = init ?? {};
const props = options.props ?? [];
const propMap = Object.fromEntries(props.map((prop) => [prop.code, prop]));
let isValidProp: (code: string) => boolean;
if (typeof extraProps === "function") {
isValidProp = (code: string) => extraProps(code) as boolean;
} else if (Array.isArray(extraProps)) {
isValidProp = (code: string) => extraProps.includes(code);
} else {
isValidProp = (_code: string) => extraProps === "any";
}
const normalizeValue = (code: string, value: any) => {
const prop = propMap[code];
if (!prop && !isValidProp(code)) return null;
if (prop?.dict) {
const parsed = parseInt(value);
return isNaN(parsed) ? value : parsed;
}
return value;
};
const normalizeModel = (newModel: Record<string, any>) =>
Object.fromEntries(
Object.entries(newModel).flatMap(([code, value]) => {
const normalized = normalizeValue(code, value);
return normalized != null ? [[code, normalized]] : [];
})
);
const handleError =
options.handleError ??
((kind, err) => {
if (kind === "validation") {
showMessage("error", "Validation Error");
} else if (kind === "internal") {
const msg = `Internal Error: ${err}`;
showMessage("error", msg);
console.error(msg);
}
});
return {
flagOnClose: null,
flagOnAdd: "add",
flagOnEdit: "edit",
data: reactive<{ dialog: any; model: Record<string, any> }>({
dialog: null,
model: { ...initValue },
}),
clearModel() {
clearAndAssign(this.data.model, initValue);
},
assignModel(newModel: Record<string, any>) {
const normalized = normalizeModel(newModel);
this.clearModel();
Object.assign(this.data.model, normalized);
},
openAdd() {
this.clearModel();
formRef?.value?.clearValidate();
this.data.dialog = this.flagOnAdd;
},
openEdit(toEdit: Record<string, any>) {
this.assignModel(toEdit);
formRef?.value?.clearValidate();
this.data.dialog = this.flagOnEdit;
},
close() {
this.data.dialog = this.flagOnClose;
},
async onConfirm() {
const value = deepCopy(this.data.model);
try {
if (this.data.dialog === this.flagOnAdd) {
await handleAdd?.(value);
} else if (this.data.dialog === this.flagOnEdit) {
await handleEdit?.(value);
}
} catch (err) {
handleError?.("internal", err);
}
this.close();
},
async onCancel() {
await handleCancel?.();
this.close();
},
};
}

43
plugs/composables/useSysDict.ts

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
import { computed } from "vue";
import { useStore } from "vuex";
export function useSysDict() {
type Callback = () => Record<string, string> | Promise<Record<string, string>>;
const store = useStore();
const callbacks: Record<string, Callback> = {};
const normalize = (content: Record<string, string>) => {
if (content == null) return {};
return Object.fromEntries(
Object.entries(content).map(([k, v]) => {
const parsed = parseInt(v);
return [k, isNaN(parsed) ? v : parsed];
})
);
};
const updateDict = async (dictIds: string[], registerCallbacks: Record<string, Callback> = {}) => {
await store.dispatch("getDictMap", dictIds);
Object.assign(callbacks, registerCallbacks);
for (const id of dictIds) {
const cb = callbacks[id];
const resp = await cb?.();
if (resp) {
store.commit("updateDict", [id, normalize(resp)]);
}
}
};
const unregister = (ids: string[]) => {
for (const id of ids) {
delete callbacks[id];
}
};
return {
sysDict: computed<Record<string, Record<string, string>>>(() => store.state.dict),
updateDict,
unregister,
};
}

12
plugs/composables/useWatchOnce.ts

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
import { nextTick, Ref, watchEffect, WatchEffect } from "vue";
export function watchEffectOnce(cond: Ref<any, any>, cb: WatchEffect) {
const stop = watchEffect((onCleanup) => {
if (cond.value) {
nextTick(() => stop());
cb(onCleanup);
}
});
return stop;
}

68
plugs/element/listTableDialog.ts

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
import { type TableColumn, ListTableDialog, handleAsync } from "noob-mengyxu";
import { ElMessageBox } from "element-plus";
import { h } from "vue";
import { PageResponse } from "../http";
type Row = Record<string, any>;
export interface ListTableProps {
props: TableColumn[];
rowKey: string;
initialPage?: number;
initialPageSize?: number;
initExample?: Record<string, any>;
useDicts?: string[];
}
interface Options {
title: string;
props: ListTableProps;
query: (example: Record<string, any>) => Promise<PageResponse<Row>>;
confirm: (rows: Row[]) => Promise<void>;
children?: any;
}
export function showListTableDialog({ title, props, query, confirm, children }: Options) {
const open = async () => {
try {
await ElMessageBox({
title,
showConfirmButton: false,
showCancelButton: false,
message: h(
ListTableDialog,
{
...props,
onQuery: handleAsync(query),
onConfirm: handleAsync(async (rows) => {
console.log("onConfirm");
await confirm(rows);
}),
onClose: handleAsync(async () => {
console.log("onClose");
ElMessageBox.close();
}),
},
children
),
customStyle: {
maxWidth: "80%",
},
});
} catch (err) {
if (err === "cancel" || err === "close") {
return;
}
throw err;
}
};
const close = () => {
ElMessageBox.close();
};
return {
open,
close,
};
}

318
plugs/http/axios3.ts

@ -0,0 +1,318 @@ @@ -0,0 +1,318 @@
/* eslint-disable */
import axios from "axios";
import * as Lang from "../i18n";
import { loading, close, showMessage } from "../element";
const { t } = Lang.i18n;
let router;
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;
};
export const registerRouter = (routerP) => {
router = routerP;
};
// 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 && val !== false) {
delete data[item];
}
}
}
}
}
// Add a response interceptor
_axios.interceptors.response.use(
function (response) {
return response.data;
},
function (error) {
return Promise.reject(error);
}
);
type QueryParams = URLSearchParams | Record<string, any> | ConstructorParameters<typeof URLSearchParams>[0];
export interface AxiosOptions {
noMsg?: boolean | null;
noLoading?: boolean | null;
filter?: (response) => any;
query?: QueryParams;
}
const defaultFilterResp = (resp) => {
const isSuccess = resp.success || resp.status === "ok" || resp.status === "success" || resp.data != null;
const isError = resp.success === false || resp.status === "error";
if (isSuccess) {
return resp.data ? resp.data : resp;
} else if (isError) {
return false;
} else return resp;
};
export function post(url, data?, options: AxiosOptions = {}) {
return new Promise((resolve, reject) => {
if (!options.noLoading) {
loading();
}
_axios.post(url, data).then(
(response: any) => {
handResponse(response, resolve, options);
},
(err) => {
handError(err, reject, options);
}
);
});
}
function mergeQueryParams(...params: Array<QueryParams>) {
const res: URLSearchParams = new URLSearchParams();
for (const param of params) {
if (param == null) continue;
let parsed;
if (param instanceof URLSearchParams) {
parsed = param;
} else {
parsed = new URLSearchParams(param);
}
parsed
.entries()
.filter(([k, v]) => v != null && v != "null" && v != "undefined" && v != "")
.forEach(([k, v]) => res?.append(k, v));
}
return res ?? new URLSearchParams();
}
export function get(url, data?: QueryParams, options: AxiosOptions = {}) {
return new Promise((resolve, reject) => {
if (!options.noLoading) {
loading();
}
_axios.get(url, { params: mergeQueryParams(data, options.query) }).then(
(response: any) => {
handResponse(response, resolve, options);
},
(err) => {
handError(err, reject, options);
}
);
});
}
export function put(url, data?, options: AxiosOptions = {}) {
return new Promise((resolve, reject) => {
if (!options.noLoading) {
loading();
}
_axios.put(url, data, { params: mergeQueryParams(options.query) }).then(
(response: any) => {
handResponse(response, resolve, options);
},
(err) => {
handError(err, reject, options);
}
);
});
}
export function delate(url, data?, options: AxiosOptions = {}) {
return new Promise((resolve, reject) => {
if (!options.noLoading) {
loading();
}
_axios({
method: "delete",
url: url,
data: data,
params: mergeQueryParams(options.query),
}).then(
(response: any) => {
handResponse(response, resolve, options);
},
(err) => {
handError(err, reject, options);
}
);
});
}
function handResponse(response, resolve, options: AxiosOptions = {}) {
if (!options.noLoading) {
close();
}
const filterResponse = options.filter ?? defaultFilterResp;
const result = filterResponse(response);
if (result) {
if (!options.noMsg && response.message) {
showMessage("success", response.message);
}
resolve(result);
} else {
if (response.message == "session timeout") {
router?.push("/login");
response.message = t("http.unLogin");
}
if (response.message == "no permission") {
response.message = t("http.unPermission");
}
if (response.message?.indexOf("no permission for ") == 0) {
response.message = t("http.noPermission");
}
if (!options.noMsg && response.message) {
showMessage("error", response.message);
}
response.error && console.log(response.error);
resolve(false);
}
}
function handError(err, reject, options: AxiosOptions = {}) {
if (!options.noLoading) {
close();
}
if (!options.noMsg) {
showMessage("error", t("http.error"));
}
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);
},
(err) => {
handError(err, reject);
}
);
});
}
export function getFile(url, data?, options: AxiosOptions = {}) {
return new Promise((resolve, reject) => {
if (!options.noLoading) {
loading();
}
_axios({
method: "get",
url: url, // 请求地址
params: data, // 参数
responseType: "blob", // 表明返回服务器返回的数据类型
}).then(
(response: any) => {
handResponse(response, resolve, options);
},
(err) => {
handError(err, reject, options);
}
);
});
}
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);
}
}
);
}

6
plugs/http/index.ts

@ -1,2 +1,4 @@ @@ -1,2 +1,4 @@
export * as Axios from './axios';
export * as Axios2 from './axios2';
export * as Axios from "./axios";
export * as Axios2 from "./axios2";
export * as Axios3 from "./axios3";
export * from "./misc";

10
plugs/http/misc.ts

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
export interface PageResponse<T> {
data: T[];
page?: number;
total: number;
}
export const pageEmpty = <T>(): PageResponse<T> => ({
data: [],
total: 0,
});

17
plugs/index.ts

@ -1,7 +1,10 @@ @@ -1,7 +1,10 @@
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';
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";
export * from "./util/asyncUtil";
export * from "./util/objectUtil";
export * from "./composables";

2
plugs/store/index.ts

@ -16,6 +16,8 @@ export class State { @@ -16,6 +16,8 @@ export class State {
style = Styles.plain;
size = Size.normal;
actions = [];
user = {};
actionPers = {};
}
export class Actions {

21
plugs/util/asyncUtil.ts

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
export type AsyncHandler<T> = {
resolve: (t: T | PromiseLike<T>) => void;
reject: (err: any) => void;
};
type ExtractResult<Args extends any[]> = Args extends [AsyncHandler<infer T>, ...any[]] ? T : never;
type ExtractArgs<Args extends any[]> = Args extends [AsyncHandler<any>, ...infer Rest] ? Rest : never;
export function useAsyncEmits<Emits extends Record<string, any[]>>(emits: (evt: any, ...args: any[]) => void) {
const emitsAsync = <Evt extends keyof Emits>(evt: Evt, ...args: ExtractArgs<Emits[Evt]>) =>
new Promise<ExtractResult<Emits[Evt]>>((resolve, reject) => {
emits(evt, { resolve, reject }, ...args);
});
return emitsAsync;
}
export function handleAsync<T, Args extends any[]>(handler: (...args: Args) => Promise<T>) {
return ({ resolve, reject }: AsyncHandler<T>, ...args: Args) => handler(...args).then(resolve, reject);
}

22
plugs/util/objectUtil.ts

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
import { cloneDeep } from "lodash-es";
export function deepCopy<T = any>(obj: T): T {
return cloneDeep(obj);
}
export function clearObject(obj: Record<string, any>) {
for (const key in obj) {
delete obj[key];
}
}
export function clearAndAssign(target: Record<string, any>, source: Record<string, any>) {
clearObject(target);
Object.assign(target, source);
}
export function unnest(obj: Record<string, any>, key: string, prefix: string) {
const { [key]: toFlatten, ...rest } = obj;
const prefixed = Object.fromEntries(Object.entries(toFlatten).map(([k, v]) => [prefix.concat(k), v]));
return { ...rest, ...prefixed };
}
Loading…
Cancel
Save