提交 10ad4d5c 编写于 作者: Mosher's avatar Mosher

add:新增实体数据视图、卡片视图部件支持

上级 459e1d7c
......@@ -6,3 +6,4 @@
{{#eq ctrl.controlType "PICKUPVIEWPANEL"}}{{> @macro/front-end/views/view-control/view-pickup-panel/view-pickup-panel.hbs}}{{/eq~}}
{{#eq ctrl.controlType "TREEVIEW"}}{{> @macro/front-end/views/view-control/view-tree/view-control-tree.hbs}}{{/eq~}}
{{#eq ctrl.controlType "PANEL"}}{{> @macro/front-end/views/view-control/view-panel/view-control-panel.hbs}}{{/eq~}}
{{#eq ctrl.controlType "DATAVIEW"}}{{> @macro/front-end/views/view-control/view-dataview/view-control-dataview.hbs}}{{/eq~}}
\ No newline at end of file
{{ctrl.name}}:{
action:{
loadAction: '{{ctrl.getPSControlAction.psAppDEMethod.codeName}}',
removeAction: '{{ctrl.removePSControlAction.psAppDEMethod.codeName}}',
updateAction: '{{ctrl.updatePSControlAction.psAppDEMethod.codeName}}',
loadDraftAction: '{{ctrl.getDraftPSControlAction.psAppDEMethod.codeName}}',
createAction: '{{ctrl.createPSControlAction.psAppDEMethod.codeName}}',
fetchAction:'{{ctrl.fetchPSControlAction.psAppDEMethod.codeName}}'
}
},
\ No newline at end of file
<script setup lang="ts">
import { IActionParam, IParam } from '@core';
import { hasKey, IParam } from '@core';
interface MenuCenterProps {
menus: IParam[];
counterData?: IParam;
......@@ -33,7 +33,7 @@ const getLayout = (item: IParam ,name: string) => {
}
const hasCounter = (item: IParam): boolean => {
if (item.counterId && props.counterData && props.counterData.hasOwnProperty(item.counterId)) {
if (item.counterId && props.counterData && hasKey(props.counterData, item.counterId)) {
return true;
}
return false;
......
<script setup lang="ts">
import { IParam } from "@core";
import { IParam, hasKey } from "@core";
interface Props{
items: IParam[],
collapsed?: boolean,
......@@ -10,7 +10,7 @@ const props = withDefaults(defineProps<Props>(), {
});
const hasCounter = (item: IParam): boolean => {
if (item.counterId && props.counterData && props.counterData.hasOwnProperty(item.counterId)) {
if (item.counterId && props.counterData && hasKey(props.counterData, item.counterId)) {
return true;
}
return false;
......
<script setup lang="ts">
import { IParam, IActionParam } from "@core";
import { onBeforeMount, ref, Ref } from "vue";
import { IParam, IActionParam, hasKey } from "@core";
import { ref, Ref } from "vue";
interface ToolbarProps {
......@@ -39,7 +39,7 @@ const itemClick = (item: IParam) => {
};
const hasCounter = (item: any) => {
if (item.counterId && props.counterData && props.counterData.hasOwnProperty(item.counterId)) {
if (item.counterId && props.counterData && hasKey(props.counterData, item.counterId)) {
return true;
}
return false;
......
<script setup lang="ts">
</script>
<template>
<AppViewBaseLayout class="app-data-view-layout">
<template v-slot:header-top>
<slot name="topMessage" />
</template>
<template v-slot:header-left>
<slot name="caption" />
</template>
<template v-slot:header-content>
</template>
<template v-slot:header-right>
<div class="data-view__header-right">
<slot name="quickGroupSearch" />
<slot name="quickSearch" />
<slot name="toolbar" />
</div>
</template>
<template v-slot:header-bottom>
<div>
<slot name="quickSearchForm" />
<slot name="searchForm" />
<slot name="searchBar" />
</div>
</template>
<template v-slot:body-top>
<slot name="bodyMessage" />
</template>
<slot />
<template v-slot:footer-content>
<slot name="bottomMessage" />
</template>
</AppViewBaseLayout>
</template>
<style lang="scss">
.app-data-view-layout {
.data-view__header-right {
display: flex;
flex-wrap: nowrap;
}
}
</style>
\ No newline at end of file
import { MDViewProps } from "../md-view";
/**
* 实体数据视图输入参数
*
* @export
* @interface DataViewProps
* @extends {MDViewProps}
*/
export interface DataViewProps extends MDViewProps {}
\ No newline at end of file
import { MDViewState } from "../md-view";
/**
* 实体数据视图状态
*
* @export
* @interface DataViewState
* @extends {MDViewState}
*/
export interface DataViewState extends MDViewState { }
\ No newline at end of file
import { IParam } from "@core";
import { MDView } from "../md-view";
import { DataViewProps } from "./data-view-prop";
import { DataViewState } from "./data-view-state";
/**
* 实体数据视图
*
* @export
* @class DataView
* @extends {MDView}
*/
export class DataView extends MDView {
/**
* 实体数据视图状态
*
* @type {DataViewState}
* @memberof DataView
*/
public declare state: DataViewState;
/**
* 实体数据视图输入参数
*
* @type {DataViewProps}
* @memberof DataView
*/
public declare props: DataViewProps;
/**
* @description 列表部件
* @type {IParam}
* @memberof DataView
*/
public declare dataViewControl: IParam;
/**
* @description 处理视图初始化
* @memberof DataView
*/
public useViewInit(): void {
super.useViewInit();
this.dataViewControl = ref(null);
}
/**
* @description 获取多数据部件
* @return {*}
* @memberof DataView
*/
public getMDCtrl() {
return unref(this.dataViewControl);
}
/**
* @description 安装视图所有功能模块的方法
* @return {*}
* @memberof DataView
*/
public moduleInstall() {
const superParams = super.moduleInstall();
return {
...superParams,
dataViewControl: this.dataViewControl
};
}
}
\ No newline at end of file
export * from './data-view-prop'
export * from './data-view-state'
export * from './data-view'
\ No newline at end of file
......@@ -17,3 +17,4 @@ export * from './panel-view'
export * from './pickup-tree-view'
export * from './list-exp-view'
export * from './grid-exp-view'
export * from './data-view'
\ No newline at end of file
import { IParam } from "@core";
import { IParam, ListViewProps, ListViewState } from "@core";
import { MDView } from "../md-view";
/**
......@@ -9,6 +9,22 @@ import { MDView } from "../md-view";
*/
export class ListView extends MDView {
/**
* 实体列表视图状态
*
* @type {ListViewState}
* @memberof ListView
*/
public declare state: ListViewState;
/**
* 实体列表视图输入参数
*
* @type {ListViewProps}
* @memberof ListView
*/
public declare props: ListViewProps;
/**
* @description 列表部件
* @type {IParam}
......@@ -37,7 +53,7 @@ export class ListView extends MDView {
/**
* @description 安装视图所有功能模块的方法
* @return {*}
* @memberof GridView
* @memberof ListView
*/
public moduleInstall() {
const superParams = super.moduleInstall();
......
import { ViewBase, MainViewState, IActionParam, IParam, isExistAndNotEmpty, hasFunction } from '@core';
import { ViewBase, MainViewState, IActionParam, IParam, isExistAndNotEmpty, hasFunction, hasKey } from '@core';
/**
* 实体视图
......@@ -96,7 +96,7 @@ export class MainView extends ViewBase {
}
for (const key in this.state.toolbar) {
// 设置初始化状态
if (!this.state.toolbar.hasOwnProperty(key)) {
if (!hasKey(this.state.toolbar, key)) {
return;
}
const item = this.state.toolbar[key];
......
......@@ -320,10 +320,8 @@ export class MDView extends MainView {
* @memberof MDView
*/
public onQuickSearchEvent($event: any) {
if ($event) {
this.handleQuickSearch($event);
}
}
/**
* @description 安装视图所有功能模块的方法
......
import { MDControlProps } from "../md-control";
/**
* 实体卡片视图部件输入参数
*
* @export
* @interface DataViewControlProps
* @extends {MDControlProps}
*/
export interface DataViewControlProps extends MDControlProps {}
\ No newline at end of file
import { MDControlState } from "../md-control";
/**
* 实体卡片视图部件状态
*
* @export
* @interface DataViewControlState
* @extends {MDControlState}
*/
export interface DataViewControlState extends MDControlState {}
\ No newline at end of file
import { IParam } from "@core";
import { IActionParam } from "@core/interface";
import { Ref } from "vue";
import { ControlStateBase } from "../control-base";
import { MDControl } from "../md-control";
import { DataViewControlProps } from "./dataview-control-prop";
import { DataViewControlState } from "./dataview-control-state";
/**
* 实体卡片视图部件
*
* @export
* @class DataViewControl
* @extends {MDControl}
*/
export class DataViewControl extends MDControl {
/**
* 实体卡片视图部件状态
*
* @type {DataViewControlState}
* @memberof DataViewControl
*/
public declare state: DataViewControlState;
/**
* 实体卡片视图部件输入参数
*
* @type {DataViewControlProps}
* @memberof DataViewControl
*/
public declare props: DataViewControlProps;
/**
* @description 处理状态变化
* @memberof DataViewControl
*/
public handleStateChange() {
// 计算列表数据界面行为权限
const { items, uIActions } = toRefs(this.state);
if (items.value.length > 0 && uIActions.value && Object.keys(uIActions.value).length > 0) {
Object.keys(uIActions.value).forEach((key: string) => {
const tempActionModel = uIActions.value[key];
items.value.forEach((item: any) => {
Object.assign(item, { [key]: this.getActionAuthState(item, [tempActionModel]) });
});
})
}
// 清空选中数据,避免多次加载选中效果异常
this.state.selections = [];
// 处理分组
this.handleDataGroup();
// 处理默认选中
this.handleDefaultSelect();
}
/**
* @description 默认选中
* @private
* @memberof DataViewControl
*/
private handleDefaultSelect() {
const { selectFirstDefault, controlName } = this.state;
const { selections, items } = toRefs(this.state);
if (selectFirstDefault) {
if (items.value && items.value.length > 0) {
selections.value.push(items.value[0]);
this.emit("ctrlEvent", {
tag: controlName,
action: "selectionChange",
data: [items.value[0]],
});
}
}
}
/**
* @description 触发界面行为
* @protected
* @param {IParam} item 列表数据
* @param {IParam} action 界面行为
* @param {MouseEvent} event 鼠标源事件
* @memberof DataViewControl
*/
protected onUIAction(item: IParam, action: IParam, event: MouseEvent) {
if (!item || !action) {
console.warn("行为执行参数不足");
return;
}
const inputParam = {
context: this.state.context,
viewParams: this.state.viewParams,
data: [item],
event: event,
actionEnvironment: this
};
// 执行行为
App.getAppActionService().execute(action, inputParam);
}
/**
* 使用自定义模块
*
* @protected
* @return {*}
* @memberof DataViewControl
*/
protected useCustom() {
const { controlName } = this.state;
/**
* 数据项选中
*
* @param {IParam} item 数据项
* @param {MouseEvent} event 鼠标源事件
*/
const onDataViewItemSelected = (item: IParam, event: MouseEvent) => {
const { isMultiple } = this.state;
const { selections } = toRefs(this.state);
const index = selections.value.findIndex((selection: any) => selection.srfkey === item.srfkey);
// 存在选中则删除
if (index !== -1) {
selections.value.splice(index, 1);
} else {
// 单选清空已选中
if (!isMultiple) {
selections.value.splice(index, selections.value.length);
}
selections.value.push(item);
}
this.emit('ctrlEvent', { tag: controlName, action: 'selectionChange', data: selections.value });
}
/**
* 是否选中
*
* @param item 列表项
* @returns
*/
const isSelected = (item: IParam): boolean => {
const { selections } = toRefs(this.state);
return selections.value.findIndex((selection: any) => selection.srfkey === item.srfkey) !== -1;
}
return {
onDataViewItemSelected: onDataViewItemSelected.bind(this),
isSelected: isSelected.bind(this)
}
}
/**
* 安装部件功能模块
*
* @return {*}
* @memberof DataViewControl
*/
public moduleInstall() {
const superParams = super.moduleInstall();
return {
...superParams,
onUIAction: this.onUIAction.bind(this),
useCustom: this.useCustom.bind(this)
}
}
}
\ No newline at end of file
export * from './dataview-control-prop'
export * from './dataview-control-state'
export * from './dataview-control'
\ No newline at end of file
import { DataTypes, dateFormat, deepCopy, GridControlState, IActionParam, IParam, isExistAndNotEmpty, MDControl } from "@core";
import { DataTypes, dateFormat, deepCopy, GridControlState, hasKey, IActionParam, IParam, isExistAndNotEmpty, MDControl } from "@core";
import { createUUID } from "qx-util";
import schema, { ErrorList, FieldErrorList } from 'async-validator';
import { Ref } from "vue";
......@@ -271,7 +271,7 @@ export class GridControl extends MDControl {
);
if (response.status && response.status == 200) {
updateItem.updateDetails?.forEach((detailName: string) => {
if (detailName && items[rowIndex].hasOwnProperty(detailName)) {
if (detailName && hasKey(items[rowIndex], detailName)) {
items[rowIndex][detailName] = response.data[detailName];
}
});
......@@ -647,7 +647,7 @@ export class GridControl extends MDControl {
}
break;
}
} else if (createDV && row.hasKey(property)) {
} else if (createDV && hasKey(row, property)) {
row[property] = dataType && DataTypes.isNumber(dataType) ? Number(createDV) : createDV;
}
});
......@@ -696,7 +696,7 @@ export class GridControl extends MDControl {
}
break;
}
} else if (updateDV && row.hasKey(property)) {
} else if (updateDV && hasKey(row, property)) {
row[property] = dataType && DataTypes.isNumber(dataType) ? Number(updateDV) : updateDV;
}
});
......
......@@ -19,3 +19,4 @@ export * from './list-control'
export * from './panel-control'
export * from './list-exp-bar-control'
export * from './grid-exp-bar-control'
export * from './dataview-control'
\ No newline at end of file
import qs from "qs";
import { clearCookie, getCookie, setCookie } from "qx-util";
import { deepCopy, getSessionStorage, Http, IAppAuthService, IParam, removeSessionStorage, setSessionStorage } from "@core";
import { hasKey } from "@core/utils";
/**
* 应用权限服务基类
......@@ -161,7 +162,7 @@ export abstract class AppAuthServiceBase implements IAppAuthService {
result[dataAccAction] = 0;
}
// 主状态权限
if (mainSateOPPrivs && (Object.keys(mainSateOPPrivs).length > 0) && mainSateOPPrivs.hasOwnProperty(dataAccAction)) {
if (mainSateOPPrivs && (Object.keys(mainSateOPPrivs).length > 0) && hasKey(mainSateOPPrivs, dataAccAction)) {
result[dataAccAction] = result[dataAccAction] && mainSateOPPrivs[dataAccAction];
}
// 实体级权限
......
import { ControlServiceBase, ControlVOBase, hasFunction, IParam } from '@core';
/**
* @description 表格部件服务
* @export
* @class DataViewService
* @extends {ControlServiceBase<T>}
* @template T 部件数据对象类型
*/
export class DataViewService<T extends ControlVOBase> extends ControlServiceBase<T> {
/**
* @description 加载草稿
* @param {IParam} context 上下文
* @param {IParam} data 行为数据
* @param { action: string; isLoading?: boolean } opts 行为参数
* @return {*} {Promise<any>}
* @memberof DataViewService
*/
public async loadDraft(context: IParam, data: IParam, opts: { action: string; isLoading?: boolean }): Promise<any> {
let _entityService: any = this.entityService;
const { context: Context, data: Data } = this.handleRequestData(context, data, opts);
// todo主键
const action = hasFunction(_entityService, opts.action) ? opts.action : 'GetDraft';
const response = await _entityService[action](Context, Data, opts.isLoading);
response.data = this.newControlVO(response.data);
response.data.srfuf = '0';
return this.handleResponse(response, opts);
}
/**
* @description 加载数据
* @param {IParam} context 上下文
* @param {IParam} data 行为数据
* @param { action: string; isLoading?: boolean } opts 行为参数
* @return {*} {Promise<any>}
* @memberof DataViewService
*/
public async search(context: IParam, data: IParam, opts: { action: string; isLoading?: boolean }): Promise<any> {
let _entityService: any = this.entityService;
const { context: Context, data: Data } = this.handleRequestData(context, data, opts);
const action = hasFunction(_entityService, opts.action) ? opts.action : 'FetchDefault';
const response = await _entityService[action](Context, Data, opts.isLoading);
let resData:any[] = response.data;
for (let index = 0; index < resData.length; index++) {
resData[index] = this.newControlVO(resData[index]);
}
return this.handleResponse(response, opts);
}
/**
* @description 新建数据
* @param {IParam} context 上下文
* @param {IParam} data 行为数据
* @param { action: string; isLoading?: boolean } opts 行为参数
* @return {*} {Promise<any>}
* @memberof DataViewService
*/
public async create(context: IParam, data: IParam, opts: { action: string; isLoading?: boolean }): Promise<any> {
let _entityService: any = this.entityService;
const { context: Context, data: Data } = this.handleRequestData(context, data, opts);
const action = hasFunction(_entityService, opts.action) ? opts.action : 'Create';
const response = await _entityService[action](Context, Data, opts.isLoading);
response.data = this.newControlVO(response.data);
return this.handleResponse(response, opts);
}
/**
* @description 删除数据
* @param {IParam} context 上下文
* @param {IParam} data 行为数据
* @param { action: string; isLoading?: boolean } opts 行为参数
* @return {*} {Promise<any>}
* @memberof DataViewService
*/
public async remove(context: IParam, data: IParam, opts: { action: string; isLoading?: boolean }): Promise<any> {
let _entityService: any = this.entityService;
const { context: Context, data: Data } = this.handleRequestData(context, data, opts);
const action = hasFunction(_entityService, opts.action) ? opts.action : 'Remove';
const response = await _entityService[action](Context, Data, opts.isLoading);
response.data = this.newControlVO(response.data);
return this.handleResponse(response, opts);
}
/**
* @description 更新
* @param {*} context 上下文
* @param {*} data 行为数据
* @param { action: string; isLoading?: boolean } opts 行为参数
* @return {*} {Promise<any>}
* @memberof DataViewService
*/
public async update(context: any, data: any, opts: { action: string; isLoading?: boolean }): Promise<any> {
let _entityService: any = this.entityService;
const { context: Context, data: Data } = this.handleRequestData(context, data, opts);
const action = hasFunction(_entityService, opts.action) ? opts.action : 'Update';
const response = await _entityService[action](Context, Data, opts.isLoading);
response.data = this.newControlVO(response.data);
return this.handleResponse(response, opts);
}
/**
* 前台逻辑
*
* @param [context={}] 上下文参数
* @param [data={}] 视图参数
* @param opts
* @return {*}
*/
public async frontLogic(context: any, data: any, opts: { action: string; isLoading?: boolean }): Promise<any> {
let _entityService: any = this.entityService;
const { context: Context, data: Data } = this.handleRequestData(context, data, opts);
if (hasFunction(_entityService, opts.action)) {
const response = await _entityService[opts.action](Context, Data, opts.isLoading);
response.data = this.newControlVO(response.data);
return this.handleResponse(response, opts);
} else {
return null;
}
}
}
......@@ -3,3 +3,4 @@ export * from './edit-form-service'
export * from './grid-service'
export * from './tree-service'
export * from './list-service'
export * from './dataview-service'
\ No newline at end of file
import { IParam } from "@core";
import { hasKey } from "../util";
/**
* 视图相关处理逻辑工具类
......@@ -19,7 +20,7 @@ export class UIUtil {
const result: any[] = [];
if (!UIService) return;
for (const key in actionModel) {
if (!actionModel.hasOwnProperty(key)) {
if (!hasKey(actionModel, key)) {
return result;
}
const item = actionModel[key];
......@@ -78,7 +79,7 @@ export class UIUtil {
let value: string | null = params[name];
if (value && value.toString().startsWith('%') && value.toString().endsWith('%')) {
const key = value.substring(1, value.length - 1).toLowerCase();
if (activedata && (activedata.hasOwnProperty(key) || key in activedata)) {
if (activedata && hasKey(activedata, key)) {
value = activedata[key];
} else if (context && context[key]) {
value = context[key];
......
import { hasKey } from "../util";
export class UIActionUtil {
......@@ -33,17 +34,11 @@ export class UIActionUtil {
let value: string | null = _params[name];
if (value && typeof value === 'string' && value.startsWith('%') && value.endsWith('%')) {
const key = value.substring(1, value.length - 1);
if (
arg &&
arg.hasOwnProperty(key) &&
(Object.is(actionTarget, 'SINGLEKEY') ||
Object.is(actionTarget, 'SINGLEDATA') ||
Object.is(actionTarget, 'NONE'))
) {
if (arg && hasKey(arg, key)) {
value = arg[key] !== null && arg[key] !== undefined ? arg[key] : null;
} else if (parentContext && parentContext.hasOwnProperty(key)) {
} else if (parentContext && hasKey(parentContext, key)) {
value = parentContext[key] !== null && parentContext[key] !== undefined ? parentContext[key] : null;
} else if (parentParams && parentParams.hasOwnProperty(key)) {
} else if (parentParams && hasKey(parentParams, key)) {
value = parentParams[key] !== null && parentParams[key] !== undefined ? parentParams[key] : null;
} else {
hasProperty = false;
......@@ -64,11 +59,11 @@ export class UIActionUtil {
if (value && typeof value === 'string' && value.startsWith('%') && value.endsWith('%')) {
const key = value.substring(1, value.length - 1);
args.forEach((arg: any) => {
if (arg && arg.hasOwnProperty(key)) {
if (arg && hasKey(arg, key)) {
value = arg[key] !== null && arg[key] !== undefined ? arg[key] : null;
} else if (parentContext && parentContext.hasOwnProperty(key)) {
} else if (parentContext && hasKey(parentContext, key)) {
value = parentContext[key] !== null && parentContext[key] !== undefined ? parentContext[key] : null;
} else if (parentParams && parentParams.hasOwnProperty(key)) {
} else if (parentParams && hasKey(parentParams, key)) {
value = parentParams[key] !== null && parentParams[key] !== undefined ? parentParams[key] : null;
} else {
value = null;
......
......@@ -132,6 +132,18 @@ export function typeOf(obj: any): string {
return map[toString.call(obj)];
}
/**
* 对象是否有属性
* @description 适配使用get set的Object对象
* @export
* @param {*} obj 对象
* @param {string} key 属性标识
* @return {*} {boolean}
*/
export function hasKey(obj: any, key: string): boolean {
return obj.hasOwnProperty(key) || key in obj;
}
/**
* @description 校验值
* @param {*} value 值
......
......@@ -24,6 +24,7 @@ const routes = [
(eq appView.viewType 'DEGRIDEXPVIEW')
(eq appView.viewType 'DELISTVIEW')
(eq appView.viewType 'DELISTEXPVIEW')
(eq appView.viewType 'DEDATAVIEW')
(eq appView.viewType 'DEPANELVIEW')
(eq appView.viewType 'DETREEEXPVIEW')
(eq appView.viewType 'DETREEVIEW')
......
.app-dataview {
height: 100%;
.app-dataview-item:hover,
.app-dataview-item__selection {
box-shadow: 2px 2px 4px 2px rgba(0, 0, 0, 0.08);
}
.app-dataview-item__action {
color: #2d8cf0;
cursor: pointer;
&:not(:first-child) {
padding-left: 12px;
}
i,
img {
padding-right: 6px;
}
}
.app-dataview-item__action.disabled {
color: #d2d2d2;
cursor: no-drop;
}
.not-data {
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
justify-content: center;
}
}
\ No newline at end of file
......@@ -11,3 +11,4 @@
@use './app-panel.scss';
@use './app-pickup-view-panel.scss';
@use './app-exp-bar.scss';
@use './app-dataview.scss';
\ No newline at end of file
import {{page.codeName}} from "./{{spinalCase page.codeName}}.vue";
export default {{page.codeName}};
export const viewState = {
enableQuickSearch: {{#if page.enableQuickSearch}}{{page.enableQuickSearch}}{{else}}false{{/if}},
expandSearchForm: {{#if page.expandSearchForm}}{{page.expandSearchForm}}{{else}}false{{/if}},
{{> @macro/front-end/views/view-base-config.hbs}}
};
\ No newline at end of file
<script setup lang="ts">
import { Subject } from 'rxjs';
import { FilterOutlined } from '@ant-design/icons-vue';
import { DataView, IActionParam, IParam, IContext } from '@core';
import { viewState } from './{{spinalCase page.codeName}}-state';
{{#page.ctrls}}
{{#eq controlType "DATAVIEW"}}
import { {{codeName}}Dataview } from '@widgets/{{spinalCase psAppDataEntity.codeName}}/{{spinalCase codeName}}-dataview';
{{/eq}}
{{#if (and (eq controlType "SEARCHFORM") (eq name 'searchform'))}}
import { {{codeName}}SearchForm } from '@widgets/{{spinalCase psAppDataEntity.codeName}}/{{spinalCase codeName}}-search-form';
{{/if}}
{{#if (and (eq controlType "SEARCHFORM") (eq name 'quicksearchform'))}}
import { {{codeName}}QuickSearchForm } from '@widgets/{{spinalCase psAppDataEntity.codeName}}/{{spinalCase codeName}}-quick-search-form';
{{/if}}
{{#eq controlType "SEARCHBAR"}}
import { {{codeName}}SearchBar } from '@widgets/{{spinalCase psAppDataEntity.codeName}}/{{spinalCase codeName}}-searchBar';
{{/eq}}
{{/page.ctrls}}
// props声明和默认值处理
interface Props {
context?: IContext;
viewParams?: IParam;
openType?: "ROUTE" | "MODAL" | "EMBED";
viewSubject?: Subject<IActionParam>;
}
const props = withDefaults(defineProps<Props>(), {
openType:'ROUTE',
viewSubject: () => new Subject<IActionParam>()
})
// emit声明
interface ViewEmit {
(name: "viewEvent", value: IActionParam): void;
}
const emit = defineEmits<ViewEmit>();
// 安装功能模块,提供状态和能力方法
const dataView = new DataView(viewState, props, emit).moduleInstall();
const { state, dataViewControl, searchForm, quickSearchForm, onCtrlEvent, onToolbarEvent, onQuickGroupEvent, onQuickSearchEvent } = dataView;
{{#if page.psAppCounterRefs}}
// 计数器数据
const counterData = computed(() => {
const { counterServices } = toRefs(state);
if (counterServices && counterServices.value && counterServices.value.length) {
return counterServices.value[0].data;
}
return {};
})
{{/if}}
</script>
<template>
<AppDataViewLayout :class="['app-dataview-view', state.viewSysCss]" :showCaptionBar="state.showCaptionBar">
<template v-slot:caption>
<AppIconText class="app-view__caption" size="large" :text="state.viewCaption" />
</template>
{{#if page.enableQuickGroup}}
<template v-slot:quickGroupSearch>
<AppQuickGroup v-if="state.enableQuickGroup" :quickGroupModel="state.quickGroupPSCodeList" :context="state.context" :viewParams="state.viewParams" @onQuickGroupEvent="onQuickGroupEvent" />
</template>
{{/if}}
{{#page.ctrls}}
{{#eq controlType "TOOLBAR"}}
<template v-slot:toolbar>
<AppToolbar
mode="button"
name="{{lowerCase codeName}}"
:actionModel="state.toolbar"
{{#if page.psAppCounterRefs}}
:counterData="counterData"
{{/if}}
@onToolbarEvent="onToolbarEvent"/>
</template>
{{/eq}}
{{#if (and (eq controlType "SEARCHFORM") (eq name 'searchform'))}}
{{#if page.enableFilter}}
<template v-slot:quickSearch>
<div class='app-quick-search'>
<a-input-search v-if="state.enableQuickSearch" @search="onQuickSearchEvent" allowClear/>
<a-popover v-show="state.expandSearchForm" trigger="click" :overlayStyle="{width: '50%'}" placement="bottom">
<template #content>
<{{codeName}}SearchForm
ref="searchForm"
name="{{name}}"
:context="state.context"
:viewParams="state.viewParams"
:controlAction="state.{{camelCase name}}.action"
:viewSubject="state.viewSubject"
@ctrlEvent="onCtrlEvent"
></{{codeName}}SearchForm>
</template>
<a-button class="app-search-form__filter-button"><filter-outlined /></a-button>
</a-popover>
</div>
</template>
{{else}}
<template v-slot:searchForm>
<{{codeName}}SearchForm
v-show="state.expandSearchForm"
ref="searchForm"
name="{{name}}"
:context="state.context"
:viewParams="state.viewParams"
:controlAction="state.{{camelCase name}}.action"
:viewSubject="state.viewSubject"
@ctrlEvent="onCtrlEvent"
></{{codeName}}SearchForm>
</template>
{{/if}}
{{/if}}
{{#if (and (eq controlType "SEARCHFORM") (eq name 'quicksearchform'))}}
<template v-slot:quickSearchForm>
<{{codeName}}QuickSearchForm
ref="quickSearchForm"
name="{{name}}"
:context="state.context"
:viewParams="state.viewParams"
:controlAction="state.{{camelCase name}}.action"
:viewSubject="state.viewSubject"
@ctrlEvent="onCtrlEvent"
></{{codeName}}QuickSearchForm>
</template>
{{/if}}
{{#eq controlType "SEARCHBAR"}}
<template v-slot:searchBar>
<{{codeName}}SearchBar
:controlAction="state.{{camelCase name}}.action"
:viewSubject="state.viewSubject"/>
</template>
{{/eq}}
{{#eq controlType "DATAVIEW"}}
<{{codeName}}Dataview
ref="dataViewControl"
name="{{name}}"
:context="state.context"
:showBusyIndicator="true"
:viewParams="state.viewParams"
:controlAction="state.{{name}}.action"
:viewSubject="state.viewSubject"
:parent="dataView"
@ctrlEvent="onCtrlEvent"
></{{codeName}}Dataview>
{{/eq}}
{{/page.ctrls}}
</AppDataViewLayout>
</template>
<style lang="scss">
.app-dataview-view {
height: 100%;
width: 100%;
.app-search-form__filter-button {
transform: translateX(-2px);
}
}
</style>
\ No newline at end of file
import {{ctrl.codeName}}Dataview from "./{{spinalCase ctrl.codeName}}-dataview.vue";
export { {{ctrl.codeName}}Dataview };
import { DataViewService, ControlVOBase } from '@core';
import { {{pascalCase ctrl.psAppDataEntity.codeName}}Service } from '@api/{{spinalCase ctrl.psAppDataEntity.codeName}}/{{spinalCase ctrl.psAppDataEntity.codeName}}-service';
export class ControlVO extends ControlVOBase {
constructor(data: any) {
super(data);
// 数据视图部件自持属性
this.$ownKeys =
{{~#each ctrl.psDEDataViewDataItems as | dataItem | ~}}
{{#if @first}}[{{/if~}}
'{{lowerCase dataItem.name}}'{{#unless @last}},{{/unless}}
{{~#if @last}}];{{/if~}}
{{/each}}
}
{{#each ctrl.psDEDataViewDataItems as | dataItem |}}
{{#if dataItem.psAppDEField}}
get {{lowerCase dataItem.name}}() {
return this.$DO.{{lowerCase dataItem.psAppDEField.codeName}};
}
set {{lowerCase dataItem.name}}(value: any) {
this.$DO.{{lowerCase dataItem.psAppDEField.codeName}} = value;
}
{{/if}}
{{/each}}
}
export const ctrlState = {
controlCodeName: '{{ctrl.codeName}}',
controlName: '{{ctrl.name}}',
appEntityCodeName: '{{ctrl.psAppDataEntity.codeName}}',
appDeCodeName:'{{ctrl.psAppDataEntity.codeName}}',
appDeLogicName: '{{ctrl.psAppDataEntity.logicName}}',
appDeKeyFieldName: '{{#if ctrl.psAppDataEntity.keyPSAppDEField}}{{ctrl.psAppDataEntity.keyPSAppDEField.codeName}}{{/if}}',
appDeMajorFieldName: '{{#if ctrl.psAppDataEntity.majorPSAppDEField}}{{ctrl.psAppDataEntity.majorPSAppDEField.codeName}}{{/if}}',
controlService: new DataViewService<ControlVO>(ControlVO, new {{pascalCase ctrl.psAppDataEntity.codeName}}Service() ),
selections: [],
// 多数据部件分组
mdCtrlGroup: {
enableGroup: {{ctrl.enableGroup}},
groupMode: "{{ctrl.groupMode}}",
groupField: "{{lowerCase ctrl.groupPSAppDEField.codeName}}",
{{#if ctrl.groupPSCodeList}}
groupCodeList: {
codeListTag: "{{ctrl.groupPSCodeList.codeListTag}}",
codeListType: "{{ctrl.groupPSCodeList.codeListType}}",
},
{{/if}}
},
// 多数据部件排序
mdCtrlSort: {
noSort: {{ctrl.noSort}},
minorSortDir: "{{#if ctrl.minorSortDir}}{{ctrl.minorSortDir}}{{/if}}",
minorSortPSDEF: "{{ctrl.minorSortPSAppDEField.codeName}}",
},
// 多数据部件分页
mdCtrlPaging: {
enablePagingBar: true,
current: 1,
pageSize: {{#if ctrl.pagingSize}}{{ctrl.pagingSize}}{{else}}20{{/if}},
pagination: {}
},
{{#if ctrl.quickToolBarItems}}
{{#ctrl.quickToolBarItems}}
quickToolbar: [
{{#items}}
{ id:'{{id}}',name:'{{name}}',caption:'{{caption}}',groupExtractMode:'{{groupExtractMode}}',itemType:'{{itemType}}',noPrivDisplayMode:'{{noPrivDisplayMode}}',showIcon:{{showIcon}},showCaption:{{showCaption}},tooltip:'{{tooltip}}',disabled: false, visible: true, imgPath: '{{imgPath}}',iconClass: '{{iconClass}}',xDataControlName:'{{xDataControlName}}',{{#if uIAction}}uIAction:{codeName:'{{uIAction.codeName}}',fullCodeName:'{{uIAction.fullCodeName}}',uIActionMode:'{{uIAction.uIActionMode}}',actionTarget:'{{uIAction.actionTarget}}',uIActionTag:'{{uIAction.uIActionTag}}',dataAccessAction:'{{uIAction.dataAccessAction}}',uIActionType:'{{uIAction.uIActionType}}'}{{/if}} },
{{/items}}
],
{{/ctrl.quickToolBarItems}}
{{/if}}
{{#if ctrl.batchToolBarItems}}
{{#ctrl.batchToolBarItems}}
batchToolbar: [
{{#items}}
{ id:'{{id}}',name:'{{name}}',caption:'{{caption}}',groupExtractMode:'{{groupExtractMode}}',itemType:'{{itemType}}',noPrivDisplayMode:'{{noPrivDisplayMode}}',showIcon:{{showIcon}},showCaption:{{showCaption}},tooltip:'{{tooltip}}',disabled: false, visible: true, imgPath: '{{imgPath}}',iconClass: '{{iconClass}}',xDataControlName:'{{xDataControlName}}',{{#if uIAction}}uIAction:{codeName:'{{uIAction.codeName}}',fullCodeName:'{{uIAction.fullCodeName}}',uIActionMode:'{{uIAction.uIActionMode}}',actionTarget:'{{uIAction.actionTarget}}',uIActionTag:'{{uIAction.uIActionTag}}',dataAccessAction:'{{uIAction.dataAccessAction}}',uIActionType:'{{uIAction.uIActionType}}'}{{/if}} },
{{/items}}
],
{{/ctrl.batchToolBarItems}}
{{/if}}
// 界面行为
uIActions: {
{{#each ctrl.psDEDataViewItems as | dataViewItem |}}
{{#and (eq dataViewItem.itemType 'ACTIONITEM') dataViewItem.psDEUIActionGroup dataViewItem.psDEUIActionGroup.psUIActionGroupDetails}}
{{#dataViewItem}}
{{#each dataViewItem.psDEUIActionGroup.psUIActionGroupDetails as | uiActionDetail |}}
{{#if uiActionDetail.getPSUIAction}}
{{#uiActionDetail.getPSUIAction}}
{{uIActionTag}}: { caption: '{{caption}}', tooltip: '{{tooltip}}', showCaption: {{../showCaption}}, showIcon: {{../showIcon}}, uIActionTag: '{{uIActionTag}}', uIActionType: '{{uIActionType}}', dataAccessAction: '{{dataAccessAction}}', noPrivDisplayMode: '{{noPrivDisplayMode}}', uIActionMode: '{{uIActionMode}}', disabled: false, visible: true, {{#if coutnerId}}counterId: '{{counterId}}', {{/if}}{{#if psSysImage}}cssClass: '{{psSysImage.cssClass}}', {{#if psSysImage.cssClass}}{{/if}}{{#if psSysImage.imagePath}}imagePath: '{{psSysImage.imagePath}}'{{/if}}{{/if}} },
{{/uiActionDetail.getPSUIAction}}
{{/if}}
{{/each}}
{{/dataViewItem}}
{{/and}}
{{/each}}
}
}
\ No newline at end of file
<script setup lang="ts">
import { Subject } from 'rxjs';
import { ctrlState } from './{{spinalCase ctrl.codeName}}-dataview-state';
import { DataViewControl, IActionParam, IParam, IContext, ControlAction } from '@core';
{{#if ctrl.itemPSLayoutPanel}}
{{#ctrl.itemPSLayoutPanel}}
import { {{codeName}}Panel } from '@widgets/{{spinalCase psAppDataEntity.codeName}}/{{spinalCase codeName}}-panel';
{{/ctrl.itemPSLayoutPanel}}
{{/if}}
{{#if ctrl.batchToolBarItems}}
import AppToolbar from '@components/common/app-toolbar.vue';
{{/if}}
interface Props {
name:string,
parent: IParam;
context: IContext;
viewParams: IParam;
multiple?: boolean;
selectFirstDefault?: boolean;
controlAction: ControlAction;
showBusyIndicator?: boolean;
viewSubject: Subject<IActionParam>;
}
const props = withDefaults(defineProps < Props > (), {
viewSubject: () => new Subject < IActionParam > (),
showBusyIndicator: true,
multiple: false,
selectFirstDefault: false,
})
// emit声明
interface CtrlEmit {
(name: "ctrlEvent", value: IActionParam): void;
}
// emit声明
const emit = defineEmits<CtrlEmit>();
// 安装功能模块,提供状态和能力
const { name, state, onUIAction, newRow, remove, save, load, refresh, getData, xDataControl, exportExcel, onToolbarEvent, useCustom } = new DataViewControl(ctrlState, props, emit).moduleInstall();
const { onDataViewItemSelected, isSelected } = useCustom();
// 暴露内部状态及能力
defineExpose({ name, state, newRow, remove, save, load, refresh, getData, exportExcel });
</script>
<template>
<div class="app-dataview" ref="xDataControl">
<a-row
v-show="state.items && state.items.length > 0"
class="dataview-container"
:gutter="20"
justify="start">
<template v-for="(item, index) in state.items" :key="index">
<a-col {{#if ctrl.cardWidth}}:style="{ width: '{{ctrl.cardWidth}}px'{{#if ctrl.cardHeight}}, height: '{{ctrl.cardHeight}}px'{{/if}} }"{{else}}:span="6"{{#if ctrl.cardHeight}}:style="{ height: '{{ctrl.cardHeight}}px' }"{{/if}}{{/if}}>
<a-card :class="['app-dataview-item', isSelected(item) ? 'app-dataview-item__selection' : '']" @click="(event) => onDataViewItemSelected(item, event)">
<template #title>
\{{item.srfmajortext}}
</template>
<template v-if="state.uIActions && Object.keys(state.uIActions).length" #actions>
<div class="app-dataview-item__actions">
<template v-for="(action, index) of state.uIActions" :key="index">
<span
v-if="item[action.uIActionTag][0].visible"
:class="['app-dataview-item__action', item[action.uIActionTag][0].disabled ? 'disabled' : '']"
:title="action.tooltip ? action.tooltip : action.caption"
@click.stop="(event) => onUIAction(item, item[action.uIActionTag][0], event)">
<template v-if="action.showIcon">
<i v-if="action.cssClass" :class="action.cssClass" />
<img v-if="action.imagePath" :src="action.imagePath" />
</template>
<span v-if="action.showCaption" class="text">\{{action.caption}}</span>
</span>
</template>
</div>
</template>
<span class="app-dataview-item__description">\{{item.srfdescription}}</span>
</a-card>
</a-col>
</template>
</a-row>
<div v-if="!state.items || state.items.length === 0" class="not-data">
<span class="empty-text">
{{#if ctrl.emptyText}}
{{ctrl.emptyText}}
{{else}}
无数据
{{/if}}
</span>
{{#if ctrl.quickToolBarItems}}
<AppToolbar
mode="button"
class="app-dataview-quicktoolbar"
name="{{ctrl.quickToolBarName}}"
:actionModel="state.quickToolbar"
@onToolbarEvent="onToolbarEvent"
></AppToolbar>
{{/if}}
</div>
</div>
</template>
<style lang="scss">
</style>
\ No newline at end of file
......@@ -13,8 +13,7 @@ export class ControlVO extends ControlVOBase {
{{/each}}
}
{{#each ctrl.psDEListDataItems as | dataItem |}}
{{#each ctrl.psDEListDataItems as | dataItem |}}
{{#if dataItem.psAppDEField}}
get {{lowerCase dataItem.name}}() {
return this.$DO.{{lowerCase dataItem.psAppDEField.codeName}};
......@@ -33,7 +32,7 @@ export class ControlVO extends ControlVOBase {
}
{{/if}}
{{/each}}
{{/each}}
}
export const ctrlState = {
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册