提交 57c405a2 编写于 作者: Mosher's avatar Mosher

add:新增首页视图菜单计数器支持

上级 13aaddb5
......@@ -17,6 +17,25 @@
isLoadDefault: {{#if (or page.loadDefault (eq page.loadDefault false))}}{{page.loadDefault}}{{else}}true{{/if}},
appViewNavContexts:{{> @macro/front-end/common/navparam.hbs appNavParams=page.psAppViewNavContexts}},
appViewNavParams:{{> @macro/front-end/common/navparam.hbs appNavParams=page.psAppViewNavParams}},
{{#if page.psAppCounterRefs}}
appCounterRefs: [
{{#each page.psAppCounterRefs as | counterRef |}}
{{#if counterRef.psAppCounter}}
{{#with counterRef.psAppCounter as | counter |}}
{
id: '{{counterRef.id}}',
getAction: '{{counter.getPSAppDEAction.codeName}}',
timer: {{#if counter.timer}}{{counter.timer}}{{else}}6000{{/if}},
{{#if counter.psAppDataEntity}}
deCodeName: '{{lowerCase counter.psAppDataEntity.codeName}}'
{{/if}}
}{{#unless @last}},{{/unless}}
{{/with}}
{{/if}}
{{/each}}
],
counterServices: [],
{{/if}}
{{!-- 快速分组代码表 --}}
enableQuickGroup: {{#if page.enableQuickGroup}}true{{else}}false{{/if}},
{{#if page.quickGroupPSCodeList}}
......
import { SyncSeriesHook } from "qx-util";
import router from "@/router";
import { AppBase, IParam, ViewDetail, IApp, IOpenViewService, deepCopy, Http, IAppAuthService, IAppNotificationService, IAppFuncService, IAppActionService, IAppCodeListService } from "@core";
import { AppBase, IParam, ViewDetail, IApp, IOpenViewService, deepCopy, Http, IAppAuthService, IAppNotificationService, IAppFuncService, IAppActionService, IAppCodeListService, IAppCounterService } from "@core";
import { AppFuncConfig, AppViewConfig, AppEntityConfig } from './config';
import { DataServiceRegister, UIServiceRegister } from "./register";
import { Environment } from "@/environments/environment";
import { AppActionService, AppAuthService, AppCodeListService, AppFuncService, AppNotificationService, OpenViewService } from "@/service";
import { AppActionService, AppAuthService, AppCodeListService, AppCounterService, AppFuncService, AppNotificationService, OpenViewService } from "@/service";
export class App extends AppBase implements IApp {
......@@ -130,6 +130,19 @@ export class App extends AppBase implements IApp {
return AppCodeListService.getInstance();
}
/**
* @description 获取计数器服务
* @param {IParam} counterRef 计数器引用
* @param {IParam} [context={}] 应用上下文
* @param {IParam} [viewParams={}] 视图参数
* @return {*} {IAppCounterService}
* @memberof App
*/
public getCounterService(counterRef: IParam, context: IParam = {}, viewParams: IParam = {}): IAppCounterService {
// TODO 暂时使用构造器构造
return new AppCounterService(counterRef, context, viewParams);
}
/**
* 获取UI服务
*
......
......@@ -2,6 +2,7 @@
import { IActionParam, IParam } from '@core';
interface MenuCenterProps {
menus: IParam[];
counterData?: IParam;
}
const props = withDefaults(defineProps<MenuCenterProps>(), {});
interface menuCenterEmit {
......@@ -30,6 +31,13 @@ const getLayout = (item: IParam ,name: string) => {
return {span: xs, offset: item.layoutPos.xsOffset};
}
}
const hasCounter = (item: IParam): boolean => {
if (item.counterId && props.counterData && props.counterData.hasOwnProperty(item.counterId)) {
return true;
}
return false;
}
</script>
<template>
......@@ -43,10 +51,19 @@ const getLayout = (item: IParam ,name: string) => {
>
<template v-if="Object.is(menu.layoutPos.layout, 'FLEX')">
<a-space :size="24" class="app-menu__center--flex">
<template v-for="item in menu.items">
<a-button v-if="!item.hidden" size="large" :class="['app-menu-item', item.itemSysCss]" @click="onClick(item)">
{{ item.caption }}
</a-button>
<template v-for="(item, index) in menu.items">
<template v-if="hasCounter(item)">
<a-badge :key="index" class="app-menu__center-badge" :count="counterData[item.counterId]">
<a-button v-if="!item.hidden" size="large" :class="['app-menu-item', item.itemSysCss]" @click="onClick(item)">
{{ item.caption }}
</a-button>
</a-badge>
</template>
<template v-else>
<a-button :key="index" v-if="!item.hidden" size="large" :class="['app-menu-item', item.itemSysCss]" @click="onClick(item)">
{{ item.caption }}
</a-button>
</template>
</template>
</a-space>
</template>
......@@ -63,11 +80,27 @@ const getLayout = (item: IParam ,name: string) => {
:class="['app-menu-item', item.itemSysCss]"
@click="onClick(item)"
>
<a-button size="large">
{{ item.caption }}
</a-button>
<template v-if="hasCounter(item)">
<a-badge class="app-menu__center-badge" :count="counterData[item.counterId]">
<a-button size="large">
{{ item.caption }}
</a-button>
</a-badge>
</template>
<template v-else>
<a-button size="large">
{{ item.caption }}
</a-button>
</template>
</a-col>
</a-row>
</template>
</a-card>
</template>
<style lang="scss">
.app-menu__center-badge {
width: 100%;
}
</style>
......@@ -3,10 +3,18 @@ import { IParam } from "@core";
interface Props{
items: IParam[],
collapsed?: boolean,
counterData?: IParam
}
const props = withDefaults(defineProps<Props>(), {
collapsed: false,
});
const hasCounter = (item: IParam): boolean => {
if (item.counterId && props.counterData && props.counterData.hasOwnProperty(item.counterId)) {
return true;
}
return false;
}
</script>
<template>
......@@ -16,7 +24,16 @@ const props = withDefaults(defineProps<Props>(), {
<template #icon>
<AppIconText :iconClass="item.iconClass" :imgPath="item.imgPath" :text="collapsed ? item.caption[0] : undefined"/>
</template>
<a-tooltip :title="item.tooltip">{{item.caption}}</a-tooltip>
<a-tooltip :title="item.tooltip">
<template v-if="hasCounter(item)">
<a-badge :count="counterData[item.counterId]">
{{item.caption}}
</a-badge>
</template>
<template v-else>
{{item.caption}}
</template>
</a-tooltip>
</a-menu-item>
</template>
<template v-else>
......@@ -24,8 +41,19 @@ const props = withDefaults(defineProps<Props>(), {
<template #icon>
<AppIconText :iconClass="item.iconClass" :imgPath="item.imgPath" :text="collapsed ? item.caption[0] : undefined"/>
</template>
<template #title><a-tooltip :title="item.tooltip">{{item.caption}}</a-tooltip></template>
<AppMenuItem :items="item.items" />
<template #title>
<a-tooltip :title="item.tooltip">
<template v-if="hasCounter(item)">
<a-badge :count="counterData[item.counterId]">
{{item.caption}}
</a-badge>
</template>
<template v-else>
{{item.caption}}
</template>
</a-tooltip>
</template>
<AppMenuItem :items="item.items" :counterData="counterData" />
</a-sub-menu>
</template>
</template>
......
import { IParam } from "..";
export interface IAppCounterService {
/**
* 执行计数器
*
* @param {IParam} [context]
* @param {IParam} [viewParams]
* @return {*} {Promise<void>}
* @memberof IAppCounterService
*/
execute(context?: IParam, viewParams?: IParam): Promise<void>;
}
\ No newline at end of file
......@@ -5,4 +5,5 @@ export * from './i-open-view-service';
export * from './i-data-service-register';
export * from './i-ui-service-register';
export * from './i-app-auth-service';
export * from './i-app-code-list-service';
\ No newline at end of file
export * from './i-app-code-list-service';
export * from './i-app-counter-service';
\ No newline at end of file
import { IApp, IAppFuncService, IOpenViewService, ViewDetail } from "@core";
import { IAppActionService, IAppAuthService, IAppCodeListService, IAppNotificationService, IParam } from "@core/interface";
import { IAppActionService, IAppAuthService, IAppCodeListService, IAppCounterService, IAppNotificationService, IParam } from "@core/interface";
/**
* 应用基类
......@@ -99,6 +99,18 @@ export abstract class AppBase implements IApp {
throw new Error("Method not implemented.");
}
/**
* @description 获取计数器服务
* @param {IParam} counterRef 计数器引用
* @param {IParam} [context={}] 应用上下文
* @param {IParam} [viewParams={}] 视图参数
* @return {*} {IAppCounterService}
* @memberof AppBase
*/
public getCounterService(counterRef: IParam, context: IParam = {}, viewParams: IParam = {}): IAppCounterService {
throw new Error("Method not implemented.");
}
/**
* 获取UI服务
*
......
......@@ -200,7 +200,18 @@ export class ViewBase {
*
* @memberof ViewBase
*/
public useCounterService() { }
public useCounterService() {
const { appCounterRefs, context, viewParams } = this.state;
const { counterServices } = toRefs(this.state);
if (appCounterRefs && appCounterRefs.length) {
appCounterRefs.forEach((counterRef: IParam) => {
const counterSerivce = App.getCounterService(counterRef, context, viewParams);
counterSerivce.execute().then(() => {
counterServices.value.push(counterSerivce);
});
});
}
}
/**
* 处理部件事件
......
import { hasFunction, IParam } from "@core";
export class AppCounterService {
/**
* @description 定时器延时时间
* @protected
* @type {number}
* @memberof AppCounterService
*/
protected delayTime: number = 6000;
/**
* @description 计数器对象
* @protected
* @type {*}
* @memberof AppCounterService
*/
protected timer: any = null;
/**
* @description 获取数据行为
* @protected
* @type {string}
* @memberof AppCounterService
*/
protected getAction: string = '';
/**
* @description 计数器唯一标识
* @private
* @type {string}
* @memberof AppCounterService
*/
private counterId: string = '';
/**
* @description 计数器实体标识
* @private
* @type {string}
* @memberof AppCounterService
*/
private deCodeName: string = '';
/**
* @description 实体服务
* @private
* @type {*}
* @memberof AppCounterService
*/
private entityService: any;
/**
* @description 计数器数据
* @private
* @type {*}
* @memberof AppCounterService
*/
private counterData: any;
/**
* @description 获取计数器数据
* @readonly
* @memberof AppCounterService
*/
get data(): any {
return this.counterData;
}
/**
* Creates an instance of AppCounterService.
* @param {IParam} counterRef 计数器
* @param {IParam} [context={}] 应用上下文
* @param {IParam} [viewParams={}] 视图参数
* @memberof AppCounterService
*/
constructor (counterRef: IParam, private context: IParam = {}, private viewParams: IParam = {}) {
this.delayTime = counterRef.timer;
this.getAction = counterRef.getAction;
this.deCodeName = counterRef.deCodeName;
this.counterId = counterRef.id;
}
/**
* @description 执行计数器
* @memberof AppCounterService
*/
async execute() {
await this.getCounterData();
this.destory();
this.timer = setInterval(() => {
this.getCounterData();
}, this.delayTime);
}
/**
* @description 获取计数器数据
* @private
* @return {*}
* @memberof AppCounterService
*/
private async getCounterData() {
// 获取实体服务
if (this.deCodeName && !this.entityService) {
this.entityService = await App.getDataService(this.deCodeName, this.context);
}
if (!this.entityService || !this.getAction) {
return;
}
if (hasFunction(this.entityService, this.getAction)) {
try {
const response: any = await this.entityService[this.getAction](this.context, this.viewParams);
if (response && response.status === 200 && response.data) {
this.counterData = response.data;
}
} catch (error: any) {
console.error(error);
}
}
}
/**
* @description 销毁定时器
* @memberof AppCounterService
*/
destory() {
if (this.timer) {
clearInterval(this.timer);
}
}
}
\ No newline at end of file
......@@ -3,4 +3,5 @@ export { AppCodeListService } from './app-code-list-service';
export { AppActionService } from './app-action-service';
export { AppAuthService } from './app-auth-service';
export { AppFuncService } from './app-func-service';
export { AppNotificationService } from './app-notification-service';
\ No newline at end of file
export { AppNotificationService } from './app-notification-service';
export { AppCounterService } from './app-counter-service';
\ No newline at end of file
......@@ -37,6 +37,15 @@ const collapsed: Ref<boolean> = ref(false);
const collapsedChange = () => {
collapsed.value = !collapsed.value;
}
{{#if page.psAppCounterRefs}}
const counterData = computed(() => {
const { counterServices } = toRefs(state);
if (counterServices.value && counterServices.value.length) {
return counterServices.value[0].data;
}
return {};
})
{{/if}}
</script>
<template>
......@@ -62,6 +71,9 @@ const collapsedChange = () => {
ref="menu"
name="{{name}}"
:context="state.context"
{{#if page.psAppCounterRefs}}
:counterData="counterData"
{{/if}}
:collapsed="collapsed"
:menuAlign="state.menuAlign"
:defaultView="state.defaultView"
......
......@@ -5,7 +5,7 @@ export const ctrlState = {
defaultSelect: [],
menus: [
{{#each ctrl.psAppMenuItems as | item |}}
{{> @macro/front-end/widgets/menu-detail/include-menu.hbs type="MENUITEM" item=item}}
{{> @macro/front-end/widgets/menu-detail/include-menu.hbs type="MENUITEM" item=item}}
{{/each}}
],
funcs: App.getAllFuncs(),
......
......@@ -11,6 +11,7 @@ interface Props {
viewParams?: IParam;
parent: IParam;
viewSubject: Subject<IActionParam>;
counterData?: IParam;
}
const props = withDefaults(defineProps < Props > (), {
menuAlign: "LEFT",
......@@ -30,11 +31,11 @@ defineExpose({ name, state, load });
<template>
<div v-if="Object.is('CENTER', state.menuAlign)" class="app-menu app-menu--center{{#if ctrl.psSysCss}} {{ctrl.psSysCss.cssName}}{{/if}}">
<AppMenuCenter :menus="state.menus" @onMenuSelect="onMenuSelect" />
<AppMenuCenter :menus="state.menus" @onMenuSelect="onMenuSelect" :counterData="counterData" />
</div>
<a-menu v-else class="app-menu{{#if ctrl.psSysCss}} {{ctrl.psSysCss.cssName}}{{/if}}" v-model:openKeys="state.defaultOpens" v-model:selectedKeys="state.defaultSelect"
:mode="Object.is('LEFT', state.menuAlign) ? 'inline' : 'horizontal'" @select="onMenuSelect">
<AppMenuItem :items="state.menus" :collapsed="collapsed" />
<AppMenuItem :items="state.menus" :collapsed="collapsed" :counterData="counterData" />
</a-menu>
</template>
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册