This commit is contained in:
xuziqiang
2024-05-15 17:29:42 +08:00
commit d0155dbe3c
7296 changed files with 1832517 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
<template>
<div :key="'addForm_' + $route.name">
<a-spin :spinning="isLoading">
<page-title :title="title" />
<a-page-header>
<template #extra>
<!-- todo 隐藏取消-->
<a-button @click="navigateBack">返回</a-button>
<a-button type="primary" @click="submit" :disabled="!nsFormElRef?.validateResult">
保存</a-button
>
</template>
</a-page-header>
<div class="add-form">
<ns-form ref="nsFormElRef" v-bind="getBindValue">
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data || {}"></slot>
</template>
</ns-form>
</div>
</a-spin>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref } from 'vue';
import { http } from '/nerv-lib/util/http';
import { NsMessage } from '/nerv-lib/component/message';
import { formProps } from '/nerv-lib/component/form/form/props';
import { PropTypes } from '/nerv-lib/util/type';
import { useNavigate } from '/nerv-lib/use/use-navigate';
import { useApi, HttpRequestConfig } from '/nerv-lib/use/use-api';
import { useRoute } from 'vue-router';
export default defineComponent({
name: 'NsViewAddForm',
props: {
...formProps,
api: PropTypes.string | PropTypes.object,
title: PropTypes.string,
},
setup(props, { attrs }) {
const nsFormElRef = ref();
const isLoading = ref(false);
const { navigateBack } = useNavigate();
const { httpRequest } = useApi();
const route = useRoute();
function submit() {
nsFormElRef.value
.triggerSubmit()
.then((data: Recordable) => {
isLoading.value = true;
const { api } = props;
const { params } = route;
const requestConfig: HttpRequestConfig = { method: 'POST' };
httpRequest({ api, params: data, pathParams: params, requestConfig })
.then(() => {
isLoading.value = false;
NsMessage.success('操作成功', 1, () => {
navigateBack();
});
})
.catch(() => {
isLoading.value = false;
});
})
.catch(() => ({}));
}
const getBindValue = computed(() => ({
...attrs,
...props,
}));
return { nsFormElRef, submit, getBindValue, isLoading, navigateBack };
},
});
</script>
<style lang="less" scoped>
.ant-page-header {
padding: 0 24px;
margin-bottom: 15px;
}
:deep(.ant-page-header-heading-extra) {
margin-right: auto !important;
margin-left: 0;
}
.add-form {
padding: 0 24px;
}
:deep(
.ant-table-thead
> tr
> th:not(:last-child):not(.ant-table-selection-column):not(
.ant-table-row-expand-icon-cell
):not([colspan])::before
) {
display: none;
}
</style>

View File

@@ -0,0 +1,303 @@
<template>
<div class="ns-skeleton" :key="'detail_' + $route.name">
<page-title :title="getTitle" />
<a-page-header v-if="showBack">
<template #extra>
<a-button @click="navigateBack">返回</a-button>
</template>
</a-page-header>
<Skeleton
active
v-for="(detailGroup, index) in getDetail"
:key="index"
:loading="loading"
:paragraph="detailGroup.SkeletonParagraphProps"
:title="detailGroup.SkeletonTitleProps">
<div class="ns-detail">
<a-descriptions :title="detailGroup.title">
<template v-if="detailGroup.items">
<template v-for="(item, index) in detailGroup.items" :key="index">
<a-descriptions-item v-if="item.ifShow">
<template #label v-if="item.label">
<div v-if="item.showTip">
<a-popover title="" class="detailLabelProver">
<template #content>
<span style="margin-top: 10px; white-space: pre-wrap">{{
item.showTip
}}</span>
</template>
<span style="margin-right: 8px">{{ item.label }}</span>
<question-circle-outlined style="option: 0.8; cursor: pointer" /> </a-popover
></div>
<div v-else>{{ item.label }}</div>
</template>
<!--默认-->
<template v-if="!item.type">
<span class="ns-detail-text">{{ item.value }}</span>
</template>
<!--富文本-->
<template v-if="item.type == 'html'">
<div class="ns-detail-html" v-html="item.value"></div>
</template>
<!--链接-->
<template v-if="item.type == 'link'">
<a class="ns-detail-link" target="_blank" :href="item.value">发票链接 </a>
</template>
<!--图片 值为数组则为图片列表 可继续扩展-->
<template v-if="item.type === 'image'">
<template v-if="typeof item.value == 'object'">
<div
class="ns-detail-image-list"
v-for="src in item.value"
:key="src"
style="display: inline-block; margin: 0 5px 5px 0">
<a-image
:width="100"
:src="`/api/op/objs/ParkPic/${src}`"
fallback="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==" />
</div>
</template>
<template v-else>
<a-image
class="ns-detail-image"
:width="100"
:src="item.value"
fallback="data:image/png;base64,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" />
</template>
</template>
<!--表格-->
<template v-else-if="item.type === 'table'">
<ns-basic-table
class="ns-detail-table"
:dataSource="dataRef[item.props.listField]"
:columns="item.props.columns"
:pagination="false"
:rowKey="item.props.rowKey" />
</template>
<template v-for="slot in Object.keys($slots)" :key="slot">
<div v-if="item.type === slot" :class="`ns-detail-${slot}`">
<slot :name="slot" v-bind="item || {}" :dataRef="dataRef" :basicInfo="item">
</slot>
</div>
</template>
</a-descriptions-item>
</template>
</template>
</a-descriptions>
</div>
</Skeleton>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref, PropType, watch } from 'vue';
import { useRoute } from 'vue-router';
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
import { cloneDeep, get, isFunction, isUndefined } from 'lodash-es';
import { Skeleton } from 'ant-design-vue';
import PageTitle from '/nerv-lib/paas/component/page-title/page-title.vue';
import { PropTypes } from '/nerv-lib/util/type';
import { AxiosRequestConfig } from 'axios';
import { useApi } from '/nerv-lib/use/use-api';
import { useNavigate } from '/nerv-lib/use/use-navigate';
export interface DetailItem {
label: string;
name: string;
value?: string;
ifShow?: Boolean | Function;
format?: Function;
type?: 'image' | 'table';
props?: Recordable;
}
export interface DetailGroup {
title: string;
items: Array<DetailItem>;
}
export default defineComponent({
name: 'NsViewDetail',
props: {
detail: {
type: Array as PropType<DetailGroup[]>,
default: () => [],
},
api: {
type: [String, Object, Function] as PropType<string | Function | AxiosRequestConfig>,
default: undefined,
},
title: PropTypes.string,
showBack: PropTypes.bool.def(false),
dataHandle: Function,
},
components: { PageTitle, Skeleton, QuestionCircleOutlined },
setup(props) {
const route = useRoute();
const dataRef = ref([]);
const { navigateBack } = useNavigate();
let loading = ref<boolean>(true);
function request() {
const { api } = props;
if (api) {
const { query, params } = route;
const { httpRequest } = useApi();
httpRequest({ api, params: query, pathParams: params }).then((res) => {
dataRef.value = props.dataHandle ? props.dataHandle(res) : res;
loading.value = false;
});
}
}
const getTitle = computed(() => {
const {
params: { pageTitle },
} = route;
if (pageTitle) return pageTitle;
const { title } = props;
return title;
});
request();
const getDetail = computed(() => {
const detail = cloneDeep(props.detail);
return (detail as Array<DetailGroup>).map((group: DetailGroup) => {
const SkeletonWidth = [];
for (let i = 0; i < group.items.length; i++) {
if (group.items[i].type === 'table') {
SkeletonWidth.push('82%');
} else {
SkeletonWidth.push('20%');
}
}
const { title, items } = group;
return {
title: title,
items: items.map((item) => {
const { ifShow } = item;
item.value = get(dataRef.value, item.name);
item.ifShow = isFunction(ifShow)
? ifShow(dataRef.value)
: isUndefined(ifShow)
? true
: ifShow;
if (item.format) {
item.value = item.format(item.value, dataRef.value);
}
return item;
}),
SkeletonParagraphProps: {
rows: items.length,
width: SkeletonWidth,
},
SkeletonTitleProps: {
width: 150,
},
};
});
});
return {
dataRef,
getDetail,
loading,
getTitle,
navigateBack,
request,
};
},
methods: {
onBack() {
this.$router.go(-1);
},
},
});
</script>
<style lang="less" scoped>
.ant-page-header {
padding: 0 24px;
margin-bottom: 15px;
}
:deep(.ant-page-header-heading-extra) {
margin-right: auto !important;
margin-left: 0;
}
:deep(.ant-skeleton-paragraph) {
display: inline;
// display: flex;
// flex-wrap: wrap;
}
:deep(.ant-skeleton-paragraph li:nth-child(n)) {
float: left;
display: inline;
margin-right: 130px;
margin-top: 16px;
margin-bottom: 4px;
}
:deep(.ant-skeleton-paragraph li:nth-child(3n + 1)) {
clear: both;
display: inline;
}
:deep(.ant-skeleton-content) {
padding: 0 8px 10px 10px;
}
.ns-detail {
padding: 0 24px 24px 24px;
}
.ns-detail-table {
width: 100%;
}
:deep(.ant-table-wrapper) {
padding: 0;
}
.ns-detail-html {
:deep(table) {
border-top: 1px solid #ffffff;
border-left: 1px solid #ffffff;
}
:deep(th) {
border-right: 1px solid #ffffff;
font-size: 13px;
padding-top: 5px;
padding-bottom: 5px;
font-weight: normal;
background: #eff0f2;
}
:deep(td) {
border-top: 1px solid #ffffff;
border-right: 1px solid #ffffff;
padding-top: 5px;
padding-bottom: 5px;
font-size: 12px;
color: #606060;
text-align: center;
:deep(text) {
border-bottom: 1px solid #ffffff;
}
background: rgba(240, 242, 245, 0.5);
}
:deep(p) {
font-size: 12px;
color: #898e91;
}
}
</style>

View File

@@ -0,0 +1,102 @@
<template>
<div :key="'edieForm_' + $route.name">
<page-title :title="title" />
<a-page-header>
<template #extra>
<!-- todo 隐藏取消-->
<a-button @click="navigateBack">返回</a-button>
<a-button type="primary" @click="submit" :disabled="!nsFormElRef?.validateResult"
>保存</a-button
>
</template>
</a-page-header>
<div class="add-form">
<ns-form ref="nsFormElRef" v-bind="getBindValue" :model="data">
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data || {}"></slot>
</template>
</ns-form>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref, watch } from 'vue';
import { http } from '/nerv-lib/util/http';
import { NsMessage } from '/nerv-lib/component/message';
import { useRoute, useRouter } from 'vue-router';
import { formProps } from '/nerv-lib/component/form/form/props';
import { PropTypes } from '/nerv-lib/util/type';
import { useApi, HttpRequestConfig } from '/nerv-lib/use/use-api';
import { useNavigate } from '/nerv-lib/use/use-navigate';
export default defineComponent({
name: 'NsViewEditForm',
props: {
...formProps,
api: PropTypes.string | PropTypes.object,
getApi: PropTypes.string,
title: PropTypes.string,
},
setup(props, { attrs }) {
const nsFormElRef = ref();
const router = useRouter();
const { httpRequest } = useApi();
const route = useRoute();
const { navigateBack } = useNavigate();
const data = ref<Recordable>({});
const request = () => {
const { api, getApi } = props;
const { params, query } = route;
const requestConfig: HttpRequestConfig = { method: 'get' };
httpRequest({
api: getApi ? getApi : api,
params: query,
pathParams: params,
requestConfig,
}).then((res: Recordable) => {
data.value = res;
});
};
request();
function submit() {
nsFormElRef.value
.triggerSubmit()
.then((data: Recordable) => {
const { api } = props;
const { params } = route;
const requestConfig: HttpRequestConfig = { method: 'PUT' };
httpRequest({ api, params: data, pathParams: params, requestConfig }).then(() => {
NsMessage.success('操作成功', 1, () => {
navigateBack();
});
});
})
.catch(() => ({}));
}
const getBindValue = computed(() => ({
...attrs,
...props,
}));
return { nsFormElRef, submit, data, getBindValue, navigateBack };
},
});
</script>
<style lang="less" scoped>
.ant-page-header {
padding: 0 24px;
margin-bottom: 15px;
}
:deep(.ant-page-header-heading-extra) {
margin-right: auto !important;
margin-left: 0;
}
.add-form {
padding: 0 24px;
}
</style>

View File

@@ -0,0 +1,74 @@
<template>
<div :key="'empty_' + $route.name">
<a-page-header>
<template #extra>
<a-button @click="onBack">返回</a-button>
</template>
</a-page-header>
<div class="page-404">
<h2></h2>
<h3>该页面还在开发中</h3>
<p>请点击链接继续浏览</p>
<div class="op-list">
<router-link :to="{ name: 'root' }">返回首页</router-link>
<span>|</span>
<ns-button type="link" @click="onBack">返回上页</ns-button>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'NsViewEmpty',
setup() {},
methods: {
onBack() {
this.$router.go(-1);
},
},
});
</script>
<style lang="less" scoped>
.page-404 {
margin: 150px auto 0;
width: 500px;
text-align: center;
h2 {
font-size: 160px;
letter-spacing: 20px;
color: @primary-color;
text-align: center;
}
h3 {
padding: 10px 0;
font-size: 36px;
letter-spacing: 3px;
color: @text-color;
text-align: center;
}
p {
font-size: 14px;
color: @text-color-secondary;
}
.op-list {
border-top: 1px solid @border-color-base;
width: 76%;
margin: 0 auto;
span {
padding-left: 16px;
color: @text-color-secondary;
}
}
}
</style>

View File

@@ -0,0 +1,74 @@
<template>
<div :key="'error403_' + $route.name">
<a-page-header>
<template #extra>
<a-button @click="onBack">返回</a-button>
</template>
</a-page-header>
<div class="page-404">
<h2>403</h2>
<h3>您没有该页面的权限</h3>
<p>请联系管理员或者点击链接继续浏览</p>
<div class="op-list">
<router-link :to="{ name: 'root' }">返回首页</router-link>
<span>|</span>
<ns-button type="link" @click="onBack">返回上页</ns-button>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'NsViewError403',
setup() {},
methods: {
onBack() {
this.$router.go(-1);
},
},
});
</script>
<style lang="less" scoped>
.page-404 {
margin: 150px auto 0;
width: 500px;
text-align: center;
h2 {
font-size: 160px;
letter-spacing: 20px;
color: @primary-color;
text-align: center;
}
h3 {
padding: 10px 0;
font-size: 36px;
letter-spacing: 3px;
color: @text-color;
text-align: center;
}
p {
font-size: 14px;
color: @text-color-secondary;
}
.op-list {
border-top: 1px solid @border-color-base;
width: 76%;
margin: 0 auto;
span {
padding-left: 16px;
color: @text-color-secondary;
}
}
}
</style>

View File

@@ -0,0 +1,74 @@
<template>
<div :key="'error404_' + $route.name">
<a-page-header>
<template #extra>
<a-button @click="onBack">返回</a-button>
</template>
</a-page-header>
<div class="page-404">
<h2>404</h2>
<h3>您来到了一块未知区域</h3>
<p>请检查您输入的网址是否正确或者点击链接继续浏览</p>
<div class="op-list">
<router-link :to="{ name: 'root' }">返回首页</router-link>
<span>|</span>
<ns-button type="link" @click="onBack">返回上页</ns-button>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'NsViewError404',
setup() {},
methods: {
onBack() {
this.$router.go(-1);
},
},
});
</script>
<style lang="less" scoped>
.page-404 {
margin: 150px auto 0;
width: 500px;
text-align: center;
h2 {
font-size: 160px;
letter-spacing: 20px;
color: @primary-color;
text-align: center;
}
h3 {
padding: 10px 0;
font-size: 36px;
letter-spacing: 3px;
color: @text-color;
text-align: center;
}
p {
font-size: 14px;
color: @text-color-secondary;
}
.op-list {
border-top: 1px solid @border-color-base;
width: 76%;
margin: 0 auto;
span {
padding-left: 16px;
color: @text-color-secondary;
}
}
}
</style>

View File

@@ -0,0 +1,246 @@
<!-- @format -->
<template>
<div :key="'table_' + $route.name">
<page-title :title="getTitle" v-if="showTitle" />
<ns-table ref="nsTableRef" v-bind="getBindValue">
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
<slot :name="item" v-bind="data"> </slot>
</template>
</ns-table>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, unref, ref } from 'vue';
import { tableProps } from '/nerv-lib/component/table/props';
import { PropTypes } from '/nerv-lib/util/type';
import { cloneDeep, isArray, isUndefined } from 'lodash-es';
import { useRoute } from 'vue-router';
export default defineComponent({
name: 'NsViewListTable',
props: {
...tableProps,
title: PropTypes.string,
tableTitle: PropTypes.func,
showTitle: {
type: Boolean,
default: true,
},
},
setup(props, { attrs }) {
const nsTableRef = ref();
const route = useRoute();
const formatFilterSearch = (key, filter) => {
let selector = filter.filter((item) => {
return item.name.startsWith(key);
});
let selectorValue = selector.map((item) => {
item.name = item.name.replace(key, '');
console.log('item.value', item.value);
if (item.name) return `${item.name}=${item.value.join('|')}`;
return `${item.value.join('|')}`;
});
return selectorValue.join(',');
};
const getFormConfig = computed(() => {
const formConfig = cloneDeep(props.formConfig);
if (formConfig) {
if (isUndefined(formConfig.showAction)) {
formConfig.showAction = false;
}
if (!isArray(formConfig.schemas)) {
formConfig.schemas = [];
}
formConfig['formLayout'] = 'flex';
//过滤标签搜索组件
if (formConfig.keyFilter === true) {
formConfig.schemas.push(
{
field: 'selector',
component: 'NsInputText',
show: false,
},
{
field: 'labels',
component: 'NsInputText',
show: false,
},
{
field: 'search',
component: 'NsInputText',
show: false,
},
);
formConfig.schemas.push({
field: 'filter',
label: '关键字',
component: 'NsInputFilter',
rules: [],
componentProps: {
maxlength: 50,
allowClear: true,
api: formConfig.api,
terraceType:
typeof formConfig.terraceType != 'undefined'
? formConfig.terraceType
: 'dataSource',
isNeedHttpGet:
typeof formConfig.isNeedHttpGet != 'undefined' ? formConfig.isNeedHttpGet : true,
filterList: formConfig.filterList ? formConfig.filterList : [],
type: typeof formConfig.type != 'undefined' ? formConfig.type : '',
defaultFilterList:
typeof formConfig.defaultFilterList != 'undefined'
? formConfig.defaultFilterList
: false,
onSearch: () => {
let filter = unref(nsTableRef)?.formElRef.model.filter;
if (!filter) {
let list = ['selector', 'labels', 'search'];
list.map((elem) => {
unref(nsTableRef).formElRef.setFormModel(elem, null);
});
unref(nsTableRef)?.formElRef?.triggerSubmit();
return;
}
filter = JSON.parse(decodeURIComponent(filter));
let selectorValue = formatFilterSearch('selector=', filter);
let labelValue = formatFilterSearch('labels=', filter);
let searchValue = formatFilterSearch('search=', filter);
unref(nsTableRef).formElRef.model.selector = selectorValue || null;
unref(nsTableRef).formElRef.model.labels = labelValue || null;
unref(nsTableRef).formElRef.model.search = searchValue || null;
unref(nsTableRef).formElRef.model.filter = null;
console.log('www',unref(nsTableRef))
unref(nsTableRef)?.formElRef?.triggerSubmit();
},
onChange: (text) => {},
placeholder: '请输入关键字',
},
});
} else if (formConfig.keySearch !== false) {
formConfig.schemas.push({
field: 'search',
label: '关键字',
component: 'NsInputSearch',
rules: [
{
message: '请输入关键字',
trigger: 'change',
},
],
componentProps: {
maxlength: 50,
onSearch: () => {
unref(nsTableRef)?.formElRef?.triggerSubmit();
},
onKeydown: (event: KeyboardEvent) => {
//fix 单个input回车会提交表单 造成重复提交
if (event.key === 'Enter' || event.code === 'Enter') {
event.preventDefault();
}
},
placeholder: '请输入关键字',
},
});
}
}
return formConfig;
});
const getBindValue = computed(() => ({
// scroll: { x: 1000 },
...attrs,
...props,
enableTableSession: true,
formLayout: 'flex',
title: null,
formConfig: getFormConfig.value,
}));
const getTitle = computed(() => {
const {
params: { pageTitle },
} = route;
if (pageTitle) return pageTitle;
const { title } = props;
if (title) return title;
});
return { getBindValue, nsTableRef, getTitle };
},
methods: {
onBack() {
this.$router.go(-1);
},
},
});
</script>
<style lang="less" scoped>
:deep(.ns-form-item) {
min-width: 220px !important;
}
:deep(.ns-operate-expand) {
display: inline-block;
padding: 4px 2px !important;
border: unset !important;
}
:deep(.ns-table) {
position: relative;
.ns-table-main {
padding: 0 24px;
}
.ns-table-search {
padding: 18px 24px 0 24px;
}
//tableList组件
.ns-table-header {
width: auto;
min-width: 100px;
user-select: none;
margin-bottom: 12px;
margin-top: 18px;
text-align: left;
position: absolute !important;
left: 0;
top: -80px;
.ant-btn {
margin-left: 0;
margin-right: 6px;
}
}
.ns-form-item label {
display: none;
}
&.ns-table-no-search {
.ns-table-search {
display: none;
}
.ns-table-header {
position: relative !important;
top: 0;
}
}
}
:deep(.ns-line) {
display: none;
}
:deep(
.ant-table-thead
> tr
> th:not(:last-child):not(.ant-table-selection-column):not(
.ant-table-row-expand-icon-cell
):not([colspan])::before
) {
display: none;
}
</style>

View File

@@ -0,0 +1,198 @@
<!-- @format -->
<template>
<div class="nav-side" :key="'navSide_' + $route.name">
<div class="nav-sub" v-show="isShow">
<ul>
<li v-show="!backTo"
><span class="nav-sub-head ng-scope" translate="COMPANY">{{ title }}</span></li
>
<li v-show="backTo">
<span
class="nav-sub-head h5 ng-scope nav-sub-head-back"
style="box-sizing: border-box; cursor: pointer"
@click="navigation(backTo)">
<i class="iconfont">&#xe607;</i>
<span>返回</span>
</span>
</li>
<li v-for="(menu, index) in menus" :key="index">
<router-link
class="nav-sub-item"
active-class="nav-sub-current"
:to="{ name: menu.name }"
append>
<span>{{ menu.label }}</span>
</router-link>
</li>
</ul>
</div>
<div class="content-main">
<router-view />
</div>
</div>
</template>
<script lang="ts">
import { SideMenu, configRegist } from '/nerv-lib/paas/store/modules/config-service';
import { defineComponent } from 'vue';
// import { storeToRefs, mapWritableState } from 'pinia';
import { findIndex } from 'lodash-es';
export default defineComponent({
name: 'SideNavMultilevel',
components: {},
setup() {
const configReg = configRegist();
return {
configReg,
};
},
data(): {
title: string;
menus: Array<any>;
isShow: boolean;
backTo: string;
currName: string;
} {
return {
title: '',
menus: [],
isShow: true,
backTo: '', //是否需要返回按钮
currName: '', //标记自己当前的路由配置取值key
};
},
beforeCreate() {},
mounted() {
let sideMenu: SideMenu;
let currUrl = this.$route.name;
let activeUrl = '';
let urlMap: any[] = this.$route.path.split('/');
//订阅路由激活状态。如果有更深层级的side-nav激活就隐藏当前的菜单
this.configReg.$subscribe((mutation, state) => {
console.log('sub');
this.isShow = this.configReg.isLaster(this.currName);
});
try {
const routeMatched = this.$route.matched.reverse();
console.log(routeMatched);
routeMatched.some((el) => {
if (el.meta['sideMenus'] && !this.configReg.hasUrl(el.name)) {
sideMenu = el.meta['sideMenus'];
this.currName = el.name || '';
this.backTo = sideMenu['backTo'] || '';
this.title = sideMenu.title || '';
this.menus = sideMenu.menus;
this.isShow = true;
this.menus.forEach((item) => {
if (item.name === currUrl) {
activeUrl = item.name;
}
});
// let index = -1;
// urlMap.some((el, ind) => {
// if (el === el.name) {
// index = ind;
// }
// });
let index = findIndex(urlMap, function (o) {
return o === el.name;
});
this.configReg.setUrl(el.name, index);
return true;
}
});
//如果没有激活的路由而且是当前side-nav的默认路由就取第一个跳转
if (!activeUrl && sideMenu.name === currUrl) {
activeUrl = this.menus[0]['name'];
}
} catch (err) {
console.log(err);
}
if (activeUrl) {
this.navigation(activeUrl);
} else {
this.navigation2(this.$route.path);
}
},
unmounted() {
// configReg.activateUrls = configReg.activateUrls.filter((el) => {
// return el !== this.currName;
this.configReg.removeUrl(this.currName);
},
methods: {
navigation(url: string) {
this.$router.push({ name: url });
},
navigation2(url: string) {
this.$router.push({ path: url });
},
},
});
</script>
<style lang="less" scoped>
.nav-side {
display: flex;
height: 100%;
.nav-sub {
float: left;
// height: 100%;
overflow: auto;
width: 149px;
background-color: #f7f9fb;
.nav-sub-head {
padding-left: 16px;
padding-right: 16px;
display: inline-block;
box-sizing: border-box;
width: 100%;
font-weight: 700;
height: 56px;
line-height: 56px;
}
.nav-sub-head-back {
.iconfont {
color: #00acff !important;
display: inline-block;
transform: scale(0.7);
font-size: 12px;
}
span {
color: #00acff !important;
}
}
.nav-sub-item {
color: #212529;
display: inline-block;
box-sizing: border-box;
width: 100%;
padding-left: 16px;
padding-right: 16px;
height: 48px;
line-height: 48px;
&:hover {
background-color: #fff;
}
}
.nav-sub-current {
background-color: #fff;
color: @layout-nav-hover;
}
}
}
.content-main {
width: calc(100% - 149px);
background-color: #ffffff;
}
ul,
li {
list-style: none;
padding: 0;
}
</style>

View File

@@ -0,0 +1,403 @@
<!-- @format -->
<template>
<div class="nav-side" :key="'navSide_' + $route.name">
<div class="nav-sub" v-show="isShow && (showLayout || backTo)">
<ul style="margin: 0">
<li v-show="!backTo"
><span class="nav-sub-head ng-scope" translate="COMPANY">{{ title }}</span></li
>
<li v-show="backTo">
<span
class="nav-sub-head h5 ng-scope nav-sub-head-back"
style="box-sizing: border-box; cursor: pointer"
@click="navigation(backTo)">
<i class="iconfont">&#xe607;</i>
<span>返回</span>
</span>
</li>
</ul>
<!-- {{ menus }} -->
<a-menu
mode="inline"
class="nav-menu"
:open-keys="openKeys"
v-model:selectedKeys="selectedKeys">
<template v-for="menu in menus">
<a-sub-menu v-if="menu.submenus" :key="menu.name">
<template #title>{{ menu.label }}</template>
<a-menu-item
v-for="subMenu in menu.submenus"
:key="subMenu.name"
:class="{ 'nav-current': fullPath.indexOf(subMenu.url) != -1 }">
<router-link
class="nav-sub-item"
active-class="nav-sub-current"
:class="{ 'nav-sub-current': fullPath.indexOf(subMenu.url) != -1 }"
:to="{ name: subMenu.name }"
@click="navChange(subMenu)">
<span>{{ subMenu.label }}</span>
</router-link>
</a-menu-item>
</a-sub-menu>
<a-menu-item
v-else
:key="menu.name"
:class="{ 'nav-current': fullPath.indexOf(`${menu.url}`) != -1 }">
<router-link
class="nav-sub-item"
active-class="nav-sub-current"
:class="{ 'nav-sub-current': dealRouter(`${menu.url}`) }"
@click="navChange(menu)"
:to="{ name: menu.name }">
<span>{{ menu.label }}</span>
</router-link>
</a-menu-item>
</template>
</a-menu>
</div>
<div class="content-main">
<router-view />
</div>
</div>
</template>
<script lang="ts">
import { SideMenu, configRegist } from '/nerv-lib/paas/store/modules/config-service';
import { computed, defineComponent, inject, reactive, ref, toRefs } from 'vue';
// import { storeToRefs, mapWritableState } from 'pinia';
import { useRoute, useRouter } from 'vue-router';
import { authorizationService } from '/nerv-lib/paas/store/modules/authorization-service';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'SideNav',
components: {},
setup() {
const configReg = configRegist();
const router = useRouter();
const route = useRoute();
const menus = ref<Array<any>>([]);
const backTo = ref<String>('');
let backToHandle = ref<Function>;
const isThreeSider = ref(false);
const state = reactive({
selectedKeys: [],
});
const showLayout = inject('showLayout', true);
const dealRouter = (val: any) => {
return router.currentRoute.value.fullPath.indexOf(val) !== -1;
};
const menuNameList = computed(() => {
const { sideMenus } = route?.meta || {};
return sideMenus.menus.map((item) => item.name);
});
function navChange(url: string) {
Object.keys(sessionStorage).forEach((key) => {
const tableSession = JSON.parse(sessionStorage[key] || '{}');
if (tableSession && tableSession.name && menuNameList.value.includes(tableSession.name)) {
delete sessionStorage[key];
}
});
}
return {
dealRouter,
menus,
backTo,
router,
isThreeSider,
configReg,
...toRefs(state),
navChange,
showLayout,
backToHandle,
};
},
data(): {
title: string;
// menus: Array<any>;
isShow: boolean;
//backTo: string;
currName: string;
fullPath: string;
openKeys: string[];
} {
return {
title: '',
// menus: [],
isShow: true,
//backTo: '', //是否需要返回按钮
currName: '', //标记自己当前的路由配置取值key
fullPath: '', //当前激活路由的url
openKeys: [],
};
},
watch: {
router: {
handler() {
this.initSider();
},
deep: true,
},
},
mounted() {
this.initSider();
},
unmounted() {
this.configReg.removeUrl(this.currName);
},
methods: {
initSider() {
if (this.$route.meta.sideMenus) {
const authService = authorizationService();
const modulesRes = authService.ModulesRes;
const appInfo = cloneDeep(modulesRes.find((item) => item.app === authService.getApp()));
const moduleName = this.$route.matched[0].name as string;
const sideMenus = cloneDeep(this.$route.meta.sideMenus as SideMenu);
const name = this.$route.name;
this.fullPath = this.$route.fullPath;
this.title = sideMenus.title as string;
this.backTo = sideMenus.backTo || '';
this.backToHandle = sideMenus?.backToHandle;
this.menus = [];
this.openKeys = [];
const { projectName } = this.$route.params;
function getMenuItem(name: string) {
console.log('---', name);
const menu = sideMenus.menus.find((item) => item.name === name);
if (
menu &&
authService.checkPermission(
moduleName,
menu.name as string,
undefined,
projectName as string,
)
) {
return menu;
}
}
function getMenuItemcustom(record: object, name: string) {
const menu = sideMenus.menus.find((item) => item.name === name);
if (
menu &&
authService.checkPermission(
record.useOtherAuthority.app,
(record.useOtherAuthority.bindView
? record.useOtherAuthority.bindView
: menu.name) as string,
undefined,
projectName as string,
)
) {
return menu;
}
}
if (sideMenus.root) {
this.selectedKeys = [];
appInfo?.menus?.forEach((item: Recordable) => {
if (item.isDir) {
const _item = {
name: item.name,
label: item.label,
submenus: [],
};
let open = false;
//处理 模块受其他项目权限控制的情况
if (item.useOtherAuthority) {
item.submenus.forEach((subItem) => {
const _subItem = getMenuItemcustom(item, subItem.name);
!!_subItem && _item.submenus.push(_subItem);
if (this.fullPath.includes(subItem.url ? subItem.url : subItem.path)) {
this.selectedKeys = [subItem.name]; // 通过输入路由匹配到文件夹下的菜单,一开始须手动加入
open = true;
}
});
} else {
item.submenus.forEach((subItem) => {
const _subItem = getMenuItem(subItem.name);
!!_subItem && _item.submenus.push(_subItem);
if (this.fullPath.includes(subItem.url ? subItem.url : subItem.path)) {
this.selectedKeys = [subItem.name]; // 通过输入路由匹配到文件夹下的菜单,一开始须手动加入
open = true;
}
});
}
// if(item.submenus.length===0){
// }
if (open) this.openKeys.push(item.name);
console.log('_item1', _item);
if (_item.submenus && _item.submenus.length !== 0) {
this.menus.push(_item);
}
} else {
//如果存在isGlobal
if (item.isGlobal) {
let globalList = [];
sideMenus.menus.forEach((subItem) => {
if (subItem.app === item.name) {
globalList.push(subItem);
}
});
globalList.forEach((global) => {
const _item = authService.checkPermission(
item.name,
global.name,
undefined,
projectName as string,
);
!!_item && this.menus.push(global);
});
} else {
if (item.useOtherAuthority) {
const _item = getMenuItemcustom(item, item.name);
!!_item && this.menus.push(_item);
} else {
const _item = getMenuItem(item.name);
!!_item && this.menus.push(_item);
}
}
}
});
} else {
this.menus = sideMenus.menus.filter((menu) => {
return (
authService.checkPermission(
menu.app ? menu.app : moduleName,
menu.bindView ? menu.bindView : (menu.name as string),
undefined,
projectName as string,
) || menu.openPermission
);
});
}
console.log('--------', this.menus);
this.isShow = true;
if (name === sideMenus.name && this.menus.length > 0) {
this.$router.push({ name: this.menus[0].name });
}
}
},
navigation(url: string) {
if (this.backToHandle && Function(this.backToHandle)) {
this.backToHandle();
return;
}
//this.navChange(url);
this.$router.push({ name: url });
},
},
});
</script>
<style lang="less" scoped>
.nav-side {
display: flex;
height: 100%;
.nav-sub {
float: left;
// height: 100%;
overflow: auto;
width: 149px;
min-width: 149px;
background: @layout-sider-background !important;
background-size: cover;
.nav-sub-head {
padding-left: 16px;
padding-right: 16px;
display: inline-block;
box-sizing: border-box;
width: 100%;
font-weight: 700;
height: 56px;
line-height: 56px;
}
.nav-sub-head-back {
.iconfont {
color: #00acff !important;
display: inline-block;
transform: scale(0.7);
font-size: 12px;
}
span {
color: #00acff !important;
}
}
.nav-sub-item {
color: #212529;
display: inline-block;
box-sizing: border-box;
width: 100%;
height: 48px;
line-height: 48px;
&:hover {
background-color: #fff;
}
}
.nav-sub-current {
background-color: #fff !important;
color: @link-color !important;
}
}
:deep(.ant-menu) {
background-color: unset;
.ant-menu-item {
background-color: unset;
margin-top: 0;
&.nav-current {
background-color: #fff;
color: #00acff;
}
&:hover {
background-color: #fff;
color: #00acff;
}
&::after {
border-right: none;
}
&.ant-menu-item-selected::after {
border-right: none;
}
}
}
}
.content-main {
// width: calc(100% - 149px);
width: 100%;
min-width: 650px;
background-color: #ffffff;
overflow: auto;
}
ul,
li {
list-style: none;
padding: 0;
}
</style>