提交 41e78f34 编写于 作者: ibizdev's avatar ibizdev

ibiz4j 发布系统代码

上级 30f2197c
......@@ -24,7 +24,7 @@ export default class AuthService {
* @type {(any)}
* @memberof AuthService
*/
public defaultOPPrivs: any = { UPDATE: 1, CREATE: 1, READ: 1, DELETE: 1 };
public defaultOPPrivs: any = { UPDATE: 1, CREATE: 1, READ: 1, DELETE: 1, WFSTART:1,DENY:1,NONE:1 };
/**
* Creates an instance of AuthService.
......
import AuthService from '../auth-service';
import SDFileUIService from '@/uiservice/sdfile/sdfile-ui-service';
/**
* 文件权限服务对象基类
......@@ -10,13 +9,6 @@ import SDFileUIService from '@/uiservice/sdfile/sdfile-ui-service';
*/
export default class SDFileAuthServiceBase extends AuthService {
/**
* 所依赖UI服务
*
* @memberof SDFileAuthServiceBase
*/
public sdfileUIService:any;
/**
* Creates an instance of SDFileAuthServiceBase.
*
......@@ -25,18 +17,16 @@ export default class SDFileAuthServiceBase extends AuthService {
*/
constructor(opts: any = {}) {
super(opts);
this.sdfileUIService = new SDFileUIService(opts);
}
/**
* 根据当前数据获取实体操作标识
*
* @param {*} data 传入数据
* @param {*} mainSateOPPrivs 传入数据操作标识
* @returns {any}
* @memberof SDFileAuthServiceBase
*/
public getOPPrivs(data:any):any{
let mainSateOPPrivs:any = this.sdfileUIService.getDEMainStateOPPrivs(data);
public getOPPrivs(mainSateOPPrivs:any):any{
let curDefaultOPPrivs:any = JSON.parse(JSON.stringify(this.defaultOPPrivs));
if(mainSateOPPrivs){
Object.assign(curDefaultOPPrivs,mainSateOPPrivs);
......
......@@ -27,7 +27,7 @@
</a>
<dropdown-menu slot='list' v-if="uiActionGroup.details && Array.isArray(uiActionGroup.details)">
<dropdown-item v-for="(detail,index) in (uiActionGroup.details)" :key="index" :name="detail.name">
<span class='item' @click="doUIAction($event, detail)">
<span class='item' v-show="detail.visabled" :style="{'pointer-events':detail.disabled?'none':'auto'}" @click="doUIAction($event, detail)">
<template v-if="detail.isShowIcon">
<template v-if="detail.icon && !Object.is(detail.icon, '')">
<i :class="detail.icon" ></i>
......@@ -58,7 +58,7 @@
<span class='item-extract-mode'>
<template v-if="uiActionGroup.details && Array.isArray(uiActionGroup.details)">
<div v-for="(detail,index) in uiActionGroup.details" :key="index">
<span class='item' @click="doUIAction($event, detail)">
<span v-show="detail.visabled" :style="{'pointer-events':detail.disabled?'none':'auto'}" class='item' @click="doUIAction($event, detail)">
<template v-if="detail.isShowIcon">
<template v-if="detail.icon && !Object.is(detail.icon, '')">
<i :class="detail.icon" ></i>
......@@ -107,7 +107,7 @@
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
@Component({})
export default class AppFormGroup extends Vue {
......@@ -120,6 +120,69 @@ export default class AppFormGroup extends Vue {
*/
@Prop() public caption?: string;
/**
* 注入的UI服务
*
* @type {*}
* @memberof AppFormGroup
*/
@Prop() public uiService!: any;
/**
* 注入数据
*
* @type {*}
* @memberof AppFormGroup
*/
@Prop() public data!: any;
/**
* 监听值变化
*
* @memberof AppFormGroup
*/
@Watch('data')
onSrfupdatedateChange(newVal: any, oldVal: any) {
if((newVal !== oldVal) && this.uiActionGroup.details.length >0){
this.calcActionItemAuthState(newVal,this.uiActionGroup.details,this.uiService);
}
}
/**
* 计算界面行为项权限状态
*
* @param {*} [data] 传入数据
* @param {*} [ActionModel] 界面行为模型
* @param {*} [UIService] 界面行为服务
* @memberof AppFormGroup
*/
public calcActionItemAuthState(data:any,ActionModel:any,UIService:any){
for (const key in ActionModel) {
if (!ActionModel.hasOwnProperty(key)) {
return;
}
const _item = ActionModel[key];
if(_item && _item['dataaccaction'] && UIService && data && Object.keys(data).length >0){
let dataActionResult:any = UIService.getAllOPPrivs(data)[_item['dataaccaction']];
// 无权限:0;有权限:1
if(!dataActionResult){
// 禁用:1;隐藏:2;隐藏且默认隐藏:6
if(_item.noprivdisplaymode === 1){
_item.disabled = true;
}
if((_item.noprivdisplaymode === 2) || (_item.noprivdisplaymode === 6)){
_item.visabled = false;
}else{
_item.visabled = true;
}
}else{
_item.visabled = true;
_item.disabled = false;
}
}
}
}
/**
* 是否为管理容器
*
......
.ivu-dropdown{
cursor: pointer;
}
\ No newline at end of file
......@@ -268,6 +268,9 @@ export default class AppPicker extends Vue {
if(Object.is(this.editortype, 'dropdown')){
this.onSearch("", null, true);
}
if(!Object.is(this.editortype, 'pickup-no-ac') && !Object.is(this.editortype, 'dropdown')){
this.curvalue = this.value;
}
}
/**
......
......@@ -106,6 +106,62 @@ export default class AppRichTextEditor extends Vue {
*/
public langu: any = localStorage.getItem('local') ? localStorage.getItem('local') : 'zh-CN' ;
/**
* 上传params
*
* @type {Array<any>}
* @memberof AppRichTextEditor
*/
public upload_params: Array<any> = [];
/**
* 导出params
*
* @type {Array<any>}
* @memberof AppRichTextEditor
*/
public export_params: Array<any> = [];
/**
* 上传参数
*
* @type {string}
* @memberof AppRichTextEditor
*/
@Prop() public uploadparams?: any;
/**
* 下载参数
*
* @type {string}
* @memberof AppRichTextEditor
*/
@Prop() public exportparams?: any;
/**
* 视图参数
*
* @type {*}
* @memberof AppRichTextEditor
*/
@Prop() public viewparams!: any;
/**
* 视图上下文
*
* @type {*}
* @memberof AppRichTextEditor
*/
@Prop() public context!: any;
/**
* 表单数据
*
* @type {string}
* @memberof AppRichTextEditor
*/
@Prop() public data!: string;
/**
* 语言映射文件
*
......@@ -142,6 +198,7 @@ export default class AppRichTextEditor extends Vue {
if(this.formState) {
this.formState.subscribe(({ type, data }) => {
if (Object.is('load', type)) {
this.getParams();
if (!this.value) {
this.init();
}
......@@ -202,6 +259,7 @@ export default class AppRichTextEditor extends Vue {
if (newval) {
this.init();
}
this.getParams();
}
/**
......@@ -259,13 +317,33 @@ export default class AppRichTextEditor extends Vue {
images_upload_handler: (bolbinfo: any, success: any, failure: any) => {
const formData = new FormData();
formData.append('file', bolbinfo.blob(), bolbinfo.filename());
const _url = richtexteditor.uploadUrl;
let _url = richtexteditor.uploadUrl;
if (this.upload_params.length > 0 ) {
_url +='?';
this.upload_params.forEach((item:any,i:any)=>{
_url += `${Object.keys(item)[0]}=${Object.values(item)[0]}`;
if(i<this.upload_params.length-1){
_url += '&';
}
})
}
this.uploadUrl = _url;
richtexteditor.uploadFile(_url, formData).subscribe((file: any) => {
let downloadUrl = richtexteditor.downloadUrl;
if (file.filename) {
const id: string = file.fileid;
const url: string = `${richtexteditor.downloadUrl}/${id}`
const url: string = `${downloadUrl}/${id}`
success(url);
}
if (this.export_params.length > 0) {
downloadUrl +='?';
this.export_params.forEach((item:any,i:any)=>{
downloadUrl += `${Object.keys(item)[0]}=${Object.values(item)[0]}`;
if(i<this.export_params.length-1){
downloadUrl += '&';
}
})
}
}, (error: any) => {
console.log(error);
failure('HTTP Error: ' + error.status);
......@@ -310,6 +388,44 @@ export default class AppRichTextEditor extends Vue {
});
return subject;
}
/**
*获取上传,导出参数
*
*@memberof AppRichTextEditor
*/
public getParams(){
let uploadparams: any = JSON.parse(JSON.stringify(this.uploadparams));
let exportparams: any = JSON.parse(JSON.stringify(this.exportparams));
let upload_params: Array<string> = [];
let export_params: Array<string> = [];
let param:any = this.viewparams;
let context:any = this.context;
let _data:any = JSON.parse(this.data);
if (this.uploadparams && !Object.is(this.uploadparams, '')) {
upload_params = this.$util.computedNavData(_data,param,context,uploadparams);
}
if (this.exportparams && !Object.is(this.exportparams, '')) {
export_params = this.$util.computedNavData(_data,param,context,exportparams);
}
this.upload_params = [];
this.export_params = [];
for (const item in upload_params) {
this.upload_params.push({
[item]:upload_params[item]
})
}
for (const item in export_params) {
this.export_params.push({
[item]:export_params[item]
})
}
}
}
</script>
<style lang="less">
......
......@@ -76,6 +76,7 @@ export default class AppSlider extends Vue {
*/
@Watch('value')
public onValueChange(newVal: any, oldVal: any) {
newVal = (newVal === null) ? 0 : newVal;
this.currentVal = parseInt(newVal);
}
......
<template>
<el-select size="small" class="filter-mode" :placeholder="$t('components.filterMode.placeholder')" v-model="curVal" @change="onChange">
<el-option
v-for="mode in filterMode"
v-for="mode in fieldFilterMode"
:key="mode.value"
:label="getLabel(mode)"
:value="mode.value"
......@@ -11,7 +11,7 @@
</template>
<script lang="ts">
import { Vue, Component, Model } from "vue-property-decorator";
import { Vue, Component, Model, Prop, Watch } from "vue-property-decorator";
@Component({})
export default class FilterMode extends Vue {
......@@ -24,6 +24,19 @@ export default class FilterMode extends Vue {
*/
@Model('change') readonly value: any;
/**
* 自定义逻辑集合
*
* @type {*}
* @memberof FilterMode
*/
@Prop() modes!: any[];
@Watch('modes')
onModesChange(newVal: any) {
this.setDefValue();
}
get curVal() {
return this.value;
}
......@@ -34,6 +47,21 @@ export default class FilterMode extends Vue {
this.$emit('change', val);
}
get fieldFilterMode() {
if(this.modes && this.modes.length > 0) {
let index: number = this.modes.findIndex((mode: any) => Object.is(mode.mode, 'all'));
if(index < 0) {
let items: any[] = [];
this.modes.forEach((mode: any) => {
let item: any = this.filterMode.find((filter: any) => Object.is(filter['en-US'], mode.mode));
items.push(item);
})
return items;
}
}
return this.filterMode;
}
/**
* 过滤模式
*
......@@ -44,13 +72,13 @@ export default class FilterMode extends Vue {
// { name: 'AND', value: '$and' },
// { name: 'OR', value: '$or' },
{ 'zh-CN': '等于(=)', 'en-US': 'EQ', value: '$eq' },
{ 'zh-CN': '不等于(<>)', 'en-US': 'NE', value: '$ne' },
{ 'zh-CN': '不等于(<>)', 'en-US': 'NOTEQ', value: '$ne' },
{ 'zh-CN': '大于(>)', 'en-US': 'GT', value: '$gt' },
{ 'zh-CN': '大于等于(>=)', 'en-US': 'GE', value: '$gte' },
{ 'zh-CN': '大于等于(>=)', 'en-US': 'GTANDEQ', value: '$gte' },
{ 'zh-CN': '小于(<)', 'en-US': 'LT', value: '$lt' },
{ 'zh-CN': '小于(<=)', 'en-US': 'LE', value: '$lte' },
{ 'zh-CN': '值为空(Nil)', 'en-US': 'IS_NULL', value: '$null' },
{ 'zh-CN': '值不为空(NotNil)', 'en-US': 'IS_NOT_NULL', value: '$notNull' },
{ 'zh-CN': '小于等于(<=)', 'en-US': 'LTANDEQ', value: '$lte' },
{ 'zh-CN': '值为空(Nil)', 'en-US': 'ISNULL', value: '$null' },
{ 'zh-CN': '值不为空(NotNil)', 'en-US': 'ISNOTNULL', value: '$notNull' },
{ 'zh-CN': '值在范围中(In)', 'en-US': 'IN', value: '$in' },
{ 'zh-CN': '值不在范围中(NotIn)', 'en-US': 'NOTIN', value: '$notIn' },
{ 'zh-CN': '文本包含(%)', 'en-US': 'LIKE', value: '$like' },
......@@ -60,13 +88,37 @@ export default class FilterMode extends Vue {
// { 'zh-CN': '', en: 'NOTEXISTS', value: '$notExists' }
];
/**
* 生命周期
*
* @return {void}
* @memberof FilterMode
*/
public mounted() {
this.setDefValue()
}
/**
* 设置默认值
*
* @return {void}
* @memberof FilterMode
*/
public setDefValue() {
if(this.fieldFilterMode.length > 0) {
this.curVal = this.fieldFilterMode[0].value;
this.onChange();
}
}
/**
* 获取语言文本
*
* @return {string}
* @memberof FilterMode
*/
getLabel(mode: any): string {
public getLabel(mode: any): string {
if(this.$i18n.locale) {
return mode[this.$i18n.locale];
}
......@@ -79,7 +131,16 @@ export default class FilterMode extends Vue {
* @memberof FilterMode
*/
public onChange() {
this.$emit('mode-change', this.value);
this.$nextTick(() => {
let item: any = this.filterMode.find((filter: any) => Object.is(filter.value, this.curVal));
if(this.modes && this.modes.length > 0) {
let mode: any = this.modes.find((mode: any) => Object.is(mode.mode, item['en-US']));
if(!mode) {
mode = this.modes.find((mode: any) => Object.is(mode.mode, 'all'));
}
this.$emit('on-change', mode);
}
})
}
}
......
......@@ -15,18 +15,20 @@
</template>
<template v-else>
<div class="filter-tree-item">
<el-select size="small" class="filter-item-field" v-model="data.field" clearable :placeholder="$t('components.filterTree.placeholder')" @change="onFieldChange(data)">
<el-select size="small" class="filter-item-field" v-model="data.field" clearable :placeholder="$t('components.filterTree.placeholder')">
<el-option
v-for="item in fields"
:key="item.prop"
v-for="item in fieldItems"
:key="item.value"
:label="item.label"
:value="item.name">
:value="item.value">
</el-option>
</el-select>
<filter-mode class="filter-item-mode" v-model="data.mode"></filter-mode>
<filter-mode class="filter-item-mode" v-model="data.mode" :modes="getModes(data.field)" @on-change="onModeChange($event, data)"></filter-mode>
<div class="filter-item-value">
<i-input v-if="!data.field"></i-input>
<slot v-else :data="data"></slot>
<i-input v-if="!data.editor"></i-input>
<div v-else :key="data.editor">
<slot :data="data"></slot>
</div>
</div>
<div class="filter-tree-action">
<icon type="md-close" @click="onRemoveItem(node, data)"/>
......@@ -64,6 +66,14 @@ export default class FilterTree extends Vue {
*/
@Prop() fields: any;
/**
* 属性项集合
*
* @type {*}
* @memberof FilterTree
*/
protected fieldItems: any[] = [];
/**
* 组条件集合
*
......@@ -93,29 +103,77 @@ export default class FilterTree extends Vue {
return [root];
}
/**
* 获取语言文本
* 生命周期
*
* @return {string}
* @return {void}
* @memberof FilterTree
*/
getLabel(mode: any): string {
if(this.$i18n.locale) {
return mode[this.$i18n.locale];
public created() {
if(!this.fields) {
return;
}
return mode['zh-CN'];
this.fields.forEach((field: any) => {
let index: number = this.fieldItems.findIndex((item: any) => Object.is(item.value, field.prop));
if(index < 0) {
this.fieldItems.push({
label: field.label,
value: field.prop,
modes: this.getFieldModes(field.prop)
})
}
});
}
/**
* 属性变化
* 获取逻辑模式集合
*
* @return {*}
* @return {void}
* @memberof FilterTree
*/
public onFieldChange(data: any) {
if(!data.mode) {
data.mode = '$eq';
public getModes(field: string) {
if(this.fieldItems.length > 0) {
let item: any = this.fieldItems.find((item: any) => Object.is(item.value, field));
if(item) {
return item.modes;
}
}
return [];
}
/**
* 获取属性逻辑模式集合
*
* @return {void}
* @memberof FilterTree
*/
public getFieldModes(name: string) {
let modes: any[] = [];
for(let i = 0; i < this.fields.length; i++) {
let field: any = this.fields[i];
if(!Object.is(field.prop, name)) {
continue;
}
modes.push({
name: field.name,
mode: field.mode ? field.mode : 'all'
})
}
return modes;
}
/**
* 获取语言文本
*
* @return {string}
* @memberof FilterTree
*/
getLabel(mode: any): string {
if(this.$i18n.locale) {
return mode[this.$i18n.locale];
}
return mode['zh-CN'];
}
/**
......@@ -128,7 +186,8 @@ export default class FilterTree extends Vue {
if(data && data.children) {
data.children.push({
field: null,
mode: null
mode: null,
editor: null
});
}
}
......@@ -162,6 +221,18 @@ export default class FilterTree extends Vue {
}
}
}
/**
* 条件逻辑变化
*
* @return {*}
* @memberof FilterTree
*/
public onModeChange(mode: any, data: any) {
if(mode && data) {
data.editor = mode.name;
}
}
}
</script>
......
......@@ -106,6 +106,7 @@ export default class EditViewEngine extends ViewEngine {
this.setTabCaption(this.view.model.dataInfo,Object.is(arg.srfuf, '0'));
const newdata: boolean = !Object.is(arg.srfuf, '1');
this.calcToolbarItemState(newdata);
this.calcToolbarItemAuthState(this.transformData(arg));
}
/**
......@@ -120,6 +121,7 @@ export default class EditViewEngine extends ViewEngine {
this.setTabCaption(this.view.model.dataInfo,Object.is(arg.srfuf, '0'));
const newdata: boolean = !Object.is(arg.srfuf, '1');
this.calcToolbarItemState(newdata);
this.calcToolbarItemAuthState(this.transformData(arg));
this.view.$emit('save',arg);
this.view.$emit('viewdataschange',JSON.stringify({action:'save',status:'success',data:arg}));
}
......@@ -144,66 +146,10 @@ export default class EditViewEngine extends ViewEngine {
* @memberof EditViewEngine
*/
public doSysUIAction(tag: string, actionmode?: string): void {
// if (Object.is(tag, 'Help')) {
// this.doHelp();
// return;
// }
// if (Object.is(tag, 'SaveAndStart')) {
// this.doSaveAndStart();
// return;
// }
// if (Object.is(tag, 'SaveAndExit')) {
// this.doSaveAndExit();
// return;
// }
// if (Object.is(tag, 'SaveAndNew')) {
// this.doSaveAndNew();
// return;
// }
if (Object.is(tag, 'Save')) {
this.doSave();
return;
}
// if (Object.is(tag, 'Print')) {
// this.doPrint();
// return;
// }
// if (Object.is(tag, 'Copy')) {
// this.doCopy();
// return;
// }
// if (Object.is(tag, 'RemoveAndExit')) {
// this.doRemoveAndExit();
// return;
// }
// if (Object.is(tag, 'Refresh')) {
// this.doRefresh();
// return;
// }
// if (Object.is(tag, 'New')) {
// this.doNew();
// return;
// }
// if (Object.is(tag, 'FirstRecord')) {
// this.doMoveToRecord('first');
// return;
// }
// if (Object.is(tag, 'PrevRecord')) {
// this.doMoveToRecord('prev');
// return;
// }
// if (Object.is(tag, 'NextRecord')) {
// this.doMoveToRecord('next');
// return;
// }
// if (Object.is(tag, 'LastRecord')) {
// this.doMoveToRecord('last');
// return;
// }
// if (Object.is(tag, 'Exit') || Object.is(tag, 'Close')) {
// this.doExit();
// return;
// }
super.doSysUIAction(tag, actionmode);
}
......@@ -263,4 +209,16 @@ export default class EditViewEngine extends ViewEngine {
}
}
/**
* 转化数据
*
* @memberof EditViewEngine
*/
public transformData(arg:any){
if(!this.getForm() || !(this.getForm().transformData instanceof Function)){
return null;
}
return this.getForm().transformData(arg);
}
}
\ No newline at end of file
......@@ -150,9 +150,9 @@ export default class ListViewEngine extends MDViewEngine {
arg.srfkeys = keys;
}
const grid: any = this.getMDCtrl();
if (grid) {
grid.remove(arg);
const list: any = this.getMDCtrl();
if (list) {
list.remove(arg);
}
}
......
......@@ -358,6 +358,9 @@ export default class MDViewEngine extends ViewEngine {
}
const state = args.length > 0 && !Object.is(args[0].srfkey, '') ? false : true;
this.calcToolbarItemState(state);
if(args && args.length > 0){
this.calcToolbarItemAuthState(this.transformData(args[0]));
}
}
/**
......@@ -395,8 +398,8 @@ export default class MDViewEngine extends ViewEngine {
if (this.getSearchForm() && this.view.isExpandSearchForm) {
Object.assign(arg, this.getSearchForm().getData());
}
if (this.view && this.view.searchbar) {
Object.assign(arg, this.view.searchbar.getData());
if (this.view && this.view.$refs.searchbar && this.view.isExpandSearchForm) {
Object.assign(arg, this.view.$refs.searchbar.getData());
}
if (this.view && !this.view.isExpandSearchForm) {
Object.assign(arg, { query: this.view.query });
......@@ -436,4 +439,17 @@ export default class MDViewEngine extends ViewEngine {
return this.propertypanel;
}
/**
* 转化数据
*
* @memberof EditViewEngine
*/
public transformData(arg:any){
if(!this.getMDCtrl() || !(this.getMDCtrl().transformData instanceof Function)){
return null;
}
return this.getMDCtrl().transformData(arg);
}
}
\ No newline at end of file
......@@ -169,6 +169,44 @@ export default class ViewEngine {
if (_item.uiaction && (Object.is(_item.uiaction.target, 'SINGLEKEY') || Object.is(_item.uiaction.target, 'MULTIKEY'))) {
_item.disabled = state;
}
_item.visabled = true;
if(_item.noprivdisplaymode && _item.noprivdisplaymode === 6){
_item.visabled = false;
}
}
}
/**
* 计算工具栏权限状态
*
* @param {boolean} state
* @param {*} [dataaccaction]
* @memberof ViewEngine
*/
public calcToolbarItemAuthState(data:any){
const _this: any = this;
for (const key in _this.view.toolBarModels) {
if (!_this.view.toolBarModels.hasOwnProperty(key)) {
return;
}
const _item = _this.view.toolBarModels[key];
if(_item && _item['dataaccaction'] && _this.view.appUIService && data && Object.keys(data).length >0){
let dataActionResult:any = _this.view.appUIService.getAllOPPrivs(data)[_item['dataaccaction']];
// 无权限:0;有权限:1
if(!dataActionResult){
// 禁用:1;隐藏:2;隐藏且默认隐藏:6
if(_item.noprivdisplaymode === 1){
_this.view.toolBarModels[key].disabled = true;
}
if((_item.noprivdisplaymode === 2) || (_item.noprivdisplaymode === 6)){
_this.view.toolBarModels[key].visabled = false;
}else{
_this.view.toolBarModels[key].visabled = true;
}
}else{
_this.view.toolBarModels[key].visabled = true;
}
}
}
}
......
......@@ -10,6 +10,7 @@ export default {
success: "Success",
ok: "OK",
cancel: "Cancel",
save: "Save",
codeNotExist: 'Code list does not exist',
reqException: "Request exception",
sysException: "System abnormality",
......@@ -178,6 +179,37 @@ export default {
quarter: "Quarter",
year: "Year",
},
searchForm: {
notConfig: {
loadAction: "View search form loadAction parameter is not configured",
loaddraftAction: "View search form loaddraftAction parameter is not configured",
},
custom: "Store custom queries",
title: "Name",
},
wizardPanel: {
back: "Back",
next: "Next",
complete: "Complete",
},
viewLayoutPanel: {
appLogoutView: {
prompt1: "Dear customer, you have successfully exited the system, after",
prompt2: "seconds, we will jump to the",
logingPage: "login page",
},
appWfstepTraceView: {
title: "Application process processing record view",
},
appWfstepDataView: {
title: "Application process tracking view",
},
appLoginView: {
username: "Username",
password: "Password",
login: "Login",
},
},
},
entities: {
sdfile: sdfile_en_US,
......
......@@ -10,6 +10,7 @@ export default {
success: "成功",
ok: "确认",
cancel: "取消",
save: "保存",
codeNotExist: "代码表不存在",
reqException: "请求异常",
sysException: "系统异常",
......@@ -177,6 +178,37 @@ export default {
quarter: "季度",
year: "年",
},
searchForm: {
notConfig: {
loadAction: "视图搜索表单loadAction参数未配置",
loaddraftAction: "视图搜索表单loaddraftAction参数未配置",
},
custom: "存储自定义查询",
title: "名称",
},
wizardPanel: {
back: "上一步",
next: "下一步",
complete: "完成",
},
viewLayoutPanel: {
appLogoutView: {
prompt1: "尊敬的客户您好,您已成功退出系统,将在",
prompt2: "秒后跳转至",
logingPage: "登录页",
},
appWfstepTraceView: {
title: "应用流程处理记录视图",
},
appWfstepDataView: {
title: "应用流程跟踪视图",
},
appLoginView: {
username: "用户名",
password: "密码",
login: "登录",
},
},
},
entities: {
sdfile: sdfile_zh_CN,
......
......@@ -124,10 +124,12 @@ import { UIActionTool,Util } from '@/utils';
import NavDataService from '@/service/app/navdata-service';
import { Subject,Subscription } from 'rxjs';
import SDFileService from '@/service/sdfile/sdfile-service';
import SDFileAuthService from '@/authservice/sdfile/sdfile-auth-service';
import EditViewEngine from '@engine/view/edit-view-engine';
import SDFileUIService from '@/uiservice/sdfile/sdfile-ui-service';
@Component({
components: {
......@@ -143,6 +145,14 @@ export default class SDFileEditViewBase extends Vue {
*/
public appEntityService: SDFileService = new SDFileService;
/**
* 实体权限服务对象
*
* @type SDFileUIService
* @memberof SDFileEditViewBase
*/
public appUIService: SDFileUIService = new SDFileUIService(this.$store);
/**
* 计数器服务对象集合
......@@ -315,32 +325,32 @@ export default class SDFileEditViewBase extends Vue {
* @memberof SDFileEditView
*/
public toolBarModels: any = {
tbitem3: { name: 'tbitem3', caption: '保存', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'Save', target: '' } },
tbitem3: { name: 'tbitem3', caption: '保存', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'Save', target: '' } },
tbitem4: { name: 'tbitem4', caption: '保存并新建', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'SaveAndNew', target: '' } },
tbitem4: { name: 'tbitem4', caption: '保存并新建', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'SaveAndNew', target: '' } },
tbitem5: { name: 'tbitem5', caption: '保存并关闭', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'SaveAndExit', target: '' } },
tbitem5: { name: 'tbitem5', caption: '保存并关闭', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'SaveAndExit', target: '' } },
tbitem6: { name: 'tbitem6', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem7: { name: 'tbitem7', caption: '删除并关闭', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'RemoveAndExit', target: 'SINGLEKEY' } },
tbitem7: { name: 'tbitem7', caption: '删除并关闭', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'RemoveAndExit', target: 'SINGLEKEY' } },
tbitem8: { name: 'tbitem8', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem12: { name: 'tbitem12', caption: '新建', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'New', target: '' } },
tbitem12: { name: 'tbitem12', caption: '新建', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'New', target: '' } },
tbitem13: { name: 'tbitem13', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem14: { name: 'tbitem14', caption: '拷贝', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'Copy', target: 'SINGLEKEY' } },
tbitem14: { name: 'tbitem14', caption: '拷贝', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'Copy', target: 'SINGLEKEY' } },
tbitem16: { name: 'tbitem16', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem23: { name: 'tbitem23', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'FirstRecord', target: 'SINGLEKEY' } },
tbitem23: { name: 'tbitem23', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'FirstRecord', target: 'SINGLEKEY' } },
tbitem24: { name: 'tbitem24', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'PrevRecord', target: 'SINGLEKEY' } },
tbitem24: { name: 'tbitem24', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'PrevRecord', target: 'SINGLEKEY' } },
tbitem25: { name: 'tbitem25', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'NextRecord', target: 'SINGLEKEY' } },
tbitem25: { name: 'tbitem25', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'NextRecord', target: 'SINGLEKEY' } },
tbitem26: { name: 'tbitem26', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'LastRecord', target: 'SINGLEKEY' } },
tbitem26: { name: 'tbitem26', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'LastRecord', target: 'SINGLEKEY' } },
tbitem21: { name: 'tbitem21', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem22: { name: 'tbitem22', caption: '帮助', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'Help', target: '' } },
tbitem22: { name: 'tbitem22', caption: '帮助', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'Help', target: '' } },
};
......
......@@ -151,10 +151,12 @@ import { UIActionTool,Util } from '@/utils';
import NavDataService from '@/service/app/navdata-service';
import { Subject,Subscription } from 'rxjs';
import SDFileService from '@/service/sdfile/sdfile-service';
import SDFileAuthService from '@/authservice/sdfile/sdfile-auth-service';
import GridViewEngine from '@engine/view/grid-view-engine';
import SDFileUIService from '@/uiservice/sdfile/sdfile-ui-service';
import CodeListService from "@service/app/codelist-service";
......@@ -172,6 +174,14 @@ export default class SDFileGridViewBase extends Vue {
*/
public appEntityService: SDFileService = new SDFileService;
/**
* 实体权限服务对象
*
* @type SDFileUIService
* @memberof SDFileGridViewBase
*/
public appUIService: SDFileUIService = new SDFileUIService(this.$store);
/**
* 计数器服务对象集合
......@@ -345,29 +355,29 @@ export default class SDFileGridViewBase extends Vue {
* @memberof SDFileGridView
*/
public toolBarModels: any = {
tbitem3: { name: 'tbitem3', caption: '新建', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'New', target: '' } },
tbitem3: { name: 'tbitem3', caption: '新建', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'New', target: '' } },
tbitem4: { name: 'tbitem4', caption: '编辑', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'Edit', target: 'SINGLEKEY' } },
tbitem4: { name: 'tbitem4', caption: '编辑', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'Edit', target: 'SINGLEKEY' } },
tbitem6: { name: 'tbitem6', caption: '拷贝', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'Copy', target: 'SINGLEKEY' } },
tbitem6: { name: 'tbitem6', caption: '拷贝', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'Copy', target: 'SINGLEKEY' } },
tbitem7: { name: 'tbitem7', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem8: { name: 'tbitem8', caption: '删除', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'Remove', target: 'MULTIKEY' } },
tbitem8: { name: 'tbitem8', caption: '删除', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'Remove', target: 'MULTIKEY' } },
tbitem9: { name: 'tbitem9', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem13: { name: 'tbitem13', caption: '导出', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'ExportExcel', target: '' }, MaxRowCount: 1000 },
tbitem13: { name: 'tbitem13', caption: '导出', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'ExportExcel', target: '' }, MaxRowCount: 1000 },
tbitem10: { name: 'tbitem10', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem16: { name: 'tbitem16', caption: '其它', disabled: false, type: 'ITEMS', visabled: true, dataaccaction: '', uiaction: { } },
tbitem21: { name: 'tbitem21', caption: '导出数据模型', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'ExportModel', target: '' } },
tbitem21: { name: 'tbitem21', caption: '导出数据模型', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'ExportModel', target: '' } },
tbitem23: { name: 'tbitem23', caption: '数据导入', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'Import', target: '' } },
tbitem23: { name: 'tbitem23', caption: '数据导入', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'Import', target: '' } },
tbitem17: { name: 'tbitem17', type: 'SEPERATOR', visabled: true, dataaccaction: '', uiaction: { } },
tbitem19: { name: 'tbitem19', caption: '过滤', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'ToggleFilter', target: '' } },
tbitem19: { name: 'tbitem19', caption: '过滤', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'ToggleFilter', target: '' } },
tbitem18: { name: 'tbitem18', caption: '帮助', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:'2',dataaccaction: '', uiaction: { tag: 'Help', target: '' } },
tbitem18: { name: 'tbitem18', caption: '帮助', disabled: false, type: 'DEUIACTION', visabled: true,noprivdisplaymode:2,dataaccaction: '', uiaction: { tag: 'Help', target: '' } },
};
......
......@@ -700,6 +700,7 @@ export default class SDIndexViewBase extends Vue {
let left_move :any= document.getElementById("left_move");
let right_move :any= document.getElementById("right_move");
let movebox :any= document.getElementById("movebox");
let leftWidth :number = parseInt(left_move.style.width);
move_axis.onmousedown = (e:any) =>{
let startX = e.clientX;
move_axis.left = move_axis.offsetLeft;
......@@ -712,6 +713,15 @@ export default class SDIndexViewBase extends Vue {
move_axis.style.left = moveLen;
left_move.style.width = moveLen + "px";
right_move.style.width = (movebox.clientWidth - moveLen - 5) + "px";
if (moveLen>500) {
left_move.style.width = 500 + 'px';
}
let left_width : number = parseInt(left_move.style.width);
move_axis.style.left = left_width - 5 + 'px';
if (left_width < leftWidth){
move_axis.style.left = leftWidth - 5 + 'px';
}
}
document.onmouseup = (evt) =>{
document.onmousemove = null;
......@@ -721,6 +731,7 @@ export default class SDIndexViewBase extends Vue {
move_axis.setCapture && move_axis.setCapture();
return false;
}
}
}
......
......@@ -105,10 +105,12 @@
}
#move_axis{
position: absolute;
left: 195px;
width: 5px;
height: 100%;
cursor: w-resize;
float: left;
background-color: rgba(255,255,255,0);
}
.index_sider{
flex: none!important;
......
......@@ -3,6 +3,7 @@ import { UIActionTool,Util } from '@/utils';
import UIService from '../ui-service';
import { Subject } from 'rxjs';
import SDFileService from '@/service/sdfile/sdfile-service';
import SDFileAuthService from '@/authservice/sdfile/sdfile-auth-service';
/**
* 文件UI服务对象基类
......@@ -76,6 +77,7 @@ export default class SDFileUIServiceBase extends UIService {
*/
constructor(opts: any = {}) {
super(opts);
this.authService = new SDFileAuthService(opts);
this.initViewMap();
this.initDeMainStateMap();
this.initDeMainStateOPPrivsMap();
......@@ -224,17 +226,27 @@ export default class SDFileUIServiceBase extends UIService {
}
/**
* 获取数据对象操作标识
* 获取数据对象当前操作标识
*
* @param curData 当前数据
* @param data 当前数据
* @memberof SDFileUIServiceBase
*/
public getDEMainStateOPPrivs(curData:any){
if(this.getDEMainStateTag(curData)){
return this.allDeMainStateOPPrivsMap.get((this.getDEMainStateTag(curData) as string));
public getDEMainStateOPPrivs(data:any){
if(this.getDEMainStateTag(data)){
return this.allDeMainStateOPPrivsMap.get((this.getDEMainStateTag(data) as string));
}else{
return null;
}
}
/**
* 获取数据对象所有的操作标识
*
* @param data 当前数据
* @memberof SDFileUIServiceBase
*/
public getAllOPPrivs(data:any){
return this.authService.getOPPrivs(this.getDEMainStateOPPrivs(data));
}
}
\ No newline at end of file
......@@ -17,6 +17,13 @@ export default class UIService {
*/
private $store: Store<any> | null = null;
/**
* 所依赖权限服务
*
* @memberof UIService
*/
public authService:any;
/**
* Creates an instance of UIService.
*
......
......@@ -93,6 +93,17 @@ export declare interface ViewTool {
* @memberof ViewTool
*/
getIndexViewParam(): any;
/**
* 计算界面行为项权限状态
*
* @static
* @param {*} [data] 传入数据
* @param {*} [ActionModel] 界面行为模型
* @param {*} [UIService] 界面行为服务
* @memberof ViewTool
*/
calcActionItemAuthState(data:any,ActionModel:any,UIService:any):any;
}
declare module "vue/types/vue" {
......
......@@ -241,4 +241,40 @@ export class ViewTool {
public static getIndexViewParam(): any {
return this.indexViewParam;
}
/**
* 计算界面行为项权限状态
*
* @static
* @param {*} [data] 传入数据
* @param {*} [ActionModel] 界面行为模型
* @param {*} [UIService] 界面行为服务
* @memberof ViewTool
*/
public static calcActionItemAuthState(data:any,ActionModel:any,UIService:any){
for (const key in ActionModel) {
if (!ActionModel.hasOwnProperty(key)) {
return;
}
const _item = ActionModel[key];
if(_item && _item['dataaccaction'] && UIService && data && Object.keys(data).length >0){
let dataActionResult:any = UIService.getAllOPPrivs(data)[_item['dataaccaction']];
// 无权限:0;有权限:1
if(!dataActionResult){
// 禁用:1;隐藏:2;隐藏且默认隐藏:6
if(_item.noprivdisplaymode === 1){
_item.disabled = true;
}
if((_item.noprivdisplaymode === 2) || (_item.noprivdisplaymode === 6)){
_item.visabled = false;
}else{
_item.visabled = true;
}
}else{
_item.visabled = true;
_item.disabled = false;
}
}
}
}
}
\ No newline at end of file
......@@ -122,11 +122,10 @@ import { Vue, Component, Prop, Provide, Emit, Watch, Model,Inject } from 'vue-pr
import { CreateElement } from 'vue';
import { Subject, Subscription } from 'rxjs';
import { ControlInterface } from '@/interface/control';
import { UIActionTool,Util } from '@/utils';
import { UIActionTool,Util,ViewTool } from '@/utils';
import NavDataService from '@/service/app/navdata-service';
import AppCenterService from "@service/app/app-center-service";
import SDIndexViewService from './sdindex-view-appmenu-service';
import SDIndexViewModel from './sdindex-view-appmenu-model';
import { Environment } from '@/environments/environment';
......
......@@ -26,12 +26,12 @@ import { Vue, Component, Prop, Provide, Emit, Watch, Model,Inject } from 'vue-pr
import { CreateElement } from 'vue';
import { Subject, Subscription } from 'rxjs';
import { ControlInterface } from '@/interface/control';
import { UIActionTool,Util } from '@/utils';
import { UIActionTool,Util,ViewTool } from '@/utils';
import NavDataService from '@/service/app/navdata-service';
import AppCenterService from "@service/app/app-center-service";
import SDFileService from '@/service/sdfile/sdfile-service';
import DefaultService from './default-searchform-service';
import SDFileUIService from '@/uiservice/sdfile/sdfile-ui-service';
import { FormButtonModel, FormPageModel, FormItemModel, FormDRUIPartModel, FormPartModel, FormGroupPanelModel, FormIFrameModel, FormRowItemModel, FormTabPageModel, FormTabPanelModel, FormUserControlModel } from '@/model/form-detail';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
......@@ -122,6 +122,19 @@ export default class DefaultBase extends Vue implements ControlInterface {
/**
* 转化数据
*
* @param {any} args
* @memberof DefaultBase
*/
public transformData(args: any) {
let _this: any = this;
if(_this.service && _this.service.handleRequestData instanceof Function && _this.service.handleRequestData('transform',_this.context,args)){
return _this.service.handleRequestData('transform',_this.context,args)['data'];
}
}
/**
* 关闭视图
*
......@@ -591,7 +604,7 @@ export default class DefaultBase extends Vue implements ControlInterface {
*/
public load(opt: any = {}): void {
if(!this.loadAction){
this.$Notice.error({ title: '错误', desc: 'SDFileGridView视图搜索表单loadAction参数未配置' });
this.$Notice.error({ title: (this.$t('app.commonWords.wrong') as string), desc: 'SDFileGridView' + (this.$t('app.searchForm.notConfig.loadAction') as string) });
return;
}
const arg: any = { ...opt };
......@@ -611,7 +624,7 @@ export default class DefaultBase extends Vue implements ControlInterface {
return;
}
if (!response || !response.status || !response.data) {
this.$Notice.error({ title: '错误', desc: '系统异常' });
this.$Notice.error({ title: (this.$t('app.commonWords.wrong') as string), desc: (this.$t('app.commonWords.sysException') as string) });
return;
}
......@@ -628,7 +641,7 @@ export default class DefaultBase extends Vue implements ControlInterface {
*/
public loadDraft(opt: any = {},mode?:string): void {
if(!this.loaddraftAction){
this.$Notice.error({ title: '错误', desc: 'SDFileGridView视图搜索表单loaddraftAction参数未配置' });
this.$Notice.error({ title: (this.$t('app.commonWords.wrong') as string), desc: 'SDFileGridView' + (this.$t('app.searchForm.notConfig.loaddraftAction') as string) });
return;
}
const arg: any = { ...opt } ;
......@@ -637,7 +650,7 @@ export default class DefaultBase extends Vue implements ControlInterface {
post.then((response: any) => {
if (!response.status || response.status !== 200) {
if (response.errorMessage) {
this.$Notice.error({ title: '错误', desc: response.errorMessage });
this.$Notice.error({ title: (this.$t('app.commonWords.wrong') as string), desc: response.errorMessage });
}
return;
}
......@@ -669,7 +682,7 @@ export default class DefaultBase extends Vue implements ControlInterface {
return;
}
if (!response || !response.status || !response.data) {
this.$Notice.error({ title: '错误', desc: '系统异常' });
this.$Notice.error({ title: (this.$t('app.commonWords.wrong') as string), desc: (this.$t('app.commonWords.sysException') as string) });
return;
}
......
......@@ -4,5 +4,5 @@ Tip: If the failing expression is known to be legally refer to something that's
----
FTL stack trace ("~" means nesting-related):
- Failed at: ${appde.getKeyPSAppDEField().getCodeN... [in template "TEMPLCODE_zh_CN" at line 1079, column 18]
- Failed at: ${appde.getKeyPSAppDEField().getCodeN... [in template "TEMPLCODE_zh_CN" at line 1105, column 18]
----
\ No newline at end of file
......@@ -4,5 +4,5 @@ Tip: If the failing expression is known to be legally refer to something that's
----
FTL stack trace ("~" means nesting-related):
- Failed at: ${ctrl.getPSAppDataEntity().getMajorP... [in template "TEMPLCODE_zh_CN" at line 903, column 39]
- Failed at: ${ctrl.getPSAppDataEntity().getMajorP... [in template "TEMPLCODE_zh_CN" at line 965, column 39]
----
\ No newline at end of file
......@@ -109,6 +109,10 @@ export default class MainModel {
name:'query',
prop:'query'
},
{
name:'filter',
prop:'filter'
},
{
name:'page',
prop:'page'
......
......@@ -106,6 +106,7 @@ public class webSecurityConfig extends WebSecurityConfigurerAdapter {
"/**/fonts/**",
"/**/js/**",
"/**/img/**",
"/**/svg/**",
"/"
).permitAll()
//放行登录请求
......
......@@ -11,6 +11,8 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.util.List;
@Slf4j
......@@ -29,6 +31,8 @@ import java.util.List;
@Import({
org.springframework.cloud.openfeign.FeignClientsConfiguration.class
})
@EnableAsync
@EnableScheduling
public class DevBootApplication extends WebMvcConfigurerAdapter{
public static void main(String[] args) {
......
......@@ -21,6 +21,7 @@ import cn.ibizlab.util.enums.DEFieldDefaultValueType;
import java.io.Serializable;
import lombok.*;
import org.springframework.data.annotation.Transient;
import cn.ibizlab.util.annotation.Audit;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
......
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
<changeSet author="Think (generated)" id="1566027230162-1">
<preConditions onFail="MARK_RAN" >
<not>
<tableExists tableName="IBZDATAAUDIT" />
</not>
</preConditions>
<createTable remarks="数据审计" tableName="IBZDATAAUDIT">
<column name="DATAAUDITID" remarks="数据审计标识" type="VARCHAR2(100 BYTE)">
<constraints primaryKey="true" primaryKeyName="SYS_C00115093"/>
</column>
<column name="OPPERSONID" remarks="操作人标识" type="VARCHAR2(100 BYTE)"/>
<column name="OPPERSONNAME" remarks="操作人名称" type="VARCHAR2(100 BYTE)"/>
<column name="AUDITTYPE" remarks="审计行为类型" type="VARCHAR2(60 BYTE)"/>
<column name="OPTIME" remarks="操作时间" type="date"/>
<column name="IPADDRESS" remarks="访问地址" type="VARCHAR2(100 BYTE)"/>
<column name="AUDITOBJECTDATA" remarks="审计对象(表数据)" type="VARCHAR2(100 BYTE)"/>
<column name="AUDITOBJECT" remarks="审计对象(表)" type="VARCHAR2(100 BYTE)"/>
<column name="AUDITINFO" remarks="审计明细" type="CLOB"/>
<column name="ISDATACHANGED" remarks="审计数据是否发生变化" type="INTEGER"/>
</createTable>
</changeSet>
</databaseChangeLog>
......@@ -10,6 +10,9 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@ConditionalOnClass(apiRestConfiguration.class)
......@@ -24,6 +27,18 @@ public class apiAutoConfiguration implements ApplicationContextAware{
this.applicationContext = applicationContext;
}
@Bean("asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(2000);
executor.setKeepAliveSeconds(600);
executor.setThreadNamePrefix("asyncExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
// @Bean
// public ServletRegistrationBean apiServlet() {
// AnnotationConfigWebApplicationContext dispatcherServletConfiguration = new AnnotationConfigWebApplicationContext();
......
......@@ -13,6 +13,8 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.util.List;
@Slf4j
......@@ -34,6 +36,8 @@ import java.util.List;
org.springframework.cloud.openfeign.FeignClientsConfiguration.class
})
@EnableFeignClients(basePackages = {"cn.ibizlab" })
@EnableAsync
@EnableScheduling
public class ibzdiskapiApplication extends WebMvcConfigurerAdapter{
public static void main(String[] args) {
......
package cn.ibizlab.util.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD})
public @interface Audit
{
}
......@@ -16,6 +16,11 @@ public @interface DEField
* @return
*/
String name() default "";
/**
* 属性名称
* @return
*/
String value() default "";
/**
* 是否为数据主键
* @return
......@@ -26,29 +31,40 @@ public @interface DEField
* @return
*/
String defaultValue() default "";
/**
* 属性类型
* @return
*/
String fieldType() default"";
/**
* 默认值类型
* @return
*/
DEFieldDefaultValueType defaultValueType() default DEFieldDefaultValueType.NONE;
/**
* 预置属性类型
* @return
*/
DEPredefinedFieldType preType() default DEPredefinedFieldType.NONE;
/**
* 逻辑删除有效值
* @return
*/
String logicval() default "";
/**
* 逻辑删除无效值
* @return
*/
String logicdelval() default "";
/**
* 代码表
* @return
*/
String dict() default "";
/**
* 日期格式化
* @return
*/
String format() default "";
}
package cn.ibizlab.util.aspect;
import lombok.SneakyThrows;
import cn.ibizlab.util.annotation.Audit;
import cn.ibizlab.util.domain.EntityBase;
import cn.ibizlab.util.helper.DEFieldCacheMap;
import cn.ibizlab.util.service.IBZDataAuditService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 实体数据审计切面类
*/
@Aspect
@Component
public class AuditAspect
{
private final ExpressionParser parser = new SpelExpressionParser();
@Autowired
IBZDataAuditService dataAuditService;
/**
* 实体数据建立切面,在成功创建数据后将新增数据内容记录审计日志内(审计明细【AuditInfo】中只记录审计属性变化情况,审计属性在平台属性中配置)
* @param point
*/
@AfterReturning(value = "execution(* cn.ibizlab.core.*.service.*.create(..))")
@SneakyThrows
public void create(JoinPoint point){
HttpServletRequest request=null;
RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
request=((ServletRequestAttributes)requestAttributes).getRequest();
}
Object [] args = point.getArgs();
if(ObjectUtils.isEmpty(args) || args.length==0)
return;
Object serviceParam =args[0];
EntityBase entity=(EntityBase)serviceParam;//创建数据
Map<String, Audit> auditFields= DEFieldCacheMap.getAuditFields(entity.getClass());
if(auditFields.size()==0)//是否有审计属性
return;
String idField=DEFieldCacheMap.getDEKeyField(entity.getClass());
Object idValue="";
if(!StringUtils.isEmpty(idField)){
idValue=entity.get(idField);
}
//记录审计日志
dataAuditService.createAudit(request,entity,idValue,auditFields);
return;
}
/**
* 实体数据更新切面,在成功更新数据后将新增数据内容记录审计日志内(审计明细【AuditInfo】中只记录审计属性变化情况,审计属性在平台属性中配置)
* 使用环切【@Around】获取到更新前后的实体数据并进行差异比较,并将差异内容记入审计日志内
* @param point
*/
@Around("execution(* cn.ibizlab.core.*.service.*.update(..))")
public Object update(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request=null;
RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
request=((ServletRequestAttributes)requestAttributes).getRequest();
}
Object serviceObj=point.getTarget();
Object args[]=point.getArgs();
if(ObjectUtils.isEmpty(args) || args.length==0)
return point.proceed();
Object arg=args[0];
EntityBase entity= (EntityBase) arg;
Map<String, Audit> auditFields= DEFieldCacheMap.getAuditFields(entity.getClass());
//是否有审计属性
if(auditFields.size()==0)
return point.proceed();
String idField=DEFieldCacheMap.getDEKeyField(entity.getClass());
Object idValue="";
if(!StringUtils.isEmpty(idField)){
idValue=entity.get(idField);
}
if(ObjectUtils.isEmpty(idValue))
return point.proceed();
//获取更新前实体
EntityBase beforeEntity=getEntity(serviceObj,idValue);
//执行更新操作
point.proceed();
//记录审计日志
dataAuditService.updateAudit(request,beforeEntity,serviceObj,idValue,auditFields);
return true;
}
/**
* 实体数据更新切面,在成功更新数据后将新增数据内容记录审计日志内(审计明细【AuditInfo】中只记录审计属性变化情况,审计属性在平台属性中配置)
* 使用环切【@Around】获取要删除的完整数据,并将审计属性相关信息记录到审计日志中
* @param point
* @return
* @throws Throwable
*/
@Around("execution(* cn.ibizlab.core.*.service.*.remove(..))")
public Object remove(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request=null;
RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
request=((ServletRequestAttributes)requestAttributes).getRequest();
}
Object serviceObj=point.getTarget();
Object args[]=point.getArgs();
if(ObjectUtils.isEmpty(args) || args.length==0)
return point.proceed();
Object idValue=args[0];
EntityBase entity=getEntity(serviceObj,idValue);
Map<String, Audit> auditFields= DEFieldCacheMap.getAuditFields(entity.getClass());
if(auditFields.size()==0){
return point.proceed();
}
else{
//执行删除操作
point.proceed();
//记录审计日志
dataAuditService.removeAudit(request,entity,idValue,auditFields);
return true;
}
}
/**
* 获取实体
* @param service
* @param id
* @return
*/
@SneakyThrows
private EntityBase getEntity(Object service, Object id){
EntityBase entity=null;
if(!ObjectUtils.isEmpty(service)){
EvaluationContext oldContext = new StandardEvaluationContext();
oldContext.setVariable("service",service);
oldContext.setVariable("id",id);
Expression oldExp = parser.parseExpression("#service.get(#id)");
return oldExp.getValue(oldContext, EntityBase.class);
}
return entity;
}
}
\ No newline at end of file
package cn.ibizlab.util.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Objects;
/**
* 实体[DataAudit] 数据对象
*/
@TableName(value = "IBZDATAAUDIT")
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class IBZDataAudit implements Serializable{
@TableId(value= "dataauditid",type=IdType.UUID)//指定主键生成策略
private String dataauditid;
private String dataauditname;
private String oppersonid;
private String oppersonname;
private String audittype;
private Timestamp optime;
private String ipaddress;
private String auditinfo;
private Object auditobjectdata;
private String auditobject;
private int isdatachanged;
}
\ No newline at end of file
package cn.ibizlab.util.helper;
import cn.ibizlab.util.annotation.Audit;
import cn.ibizlab.util.annotation.DEField;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -22,6 +23,8 @@ public class DEFieldCacheMap {
private static Hashtable<String, Hashtable<String,DEField>> cacheDEField = new Hashtable<>();
private static Hashtable<String, Hashtable<String,Audit>> cacheAuditField = new Hashtable<>();
private static Hashtable<String, String> cacheDEKeyField = new Hashtable<>();
private static Object objLock1=new Object();
......@@ -44,6 +47,7 @@ public class DEFieldCacheMap {
List<Field> list=new ArrayList<Field>();
Hashtable<String,String> keys=new Hashtable<String,String>();
Hashtable<String,DEField> defields=new Hashtable<>();
Hashtable<String, Audit> auditfields=new Hashtable<>();
Hashtable<String,String> dekeyfields=new Hashtable<>();
Field[] fields=clazz.getDeclaredFields();
for(Field field:fields){
......@@ -51,16 +55,21 @@ public class DEFieldCacheMap {
list.add(field);
keys.put(field.getName().toLowerCase(),field.getName());
DEField deField=field.getAnnotation(DEField.class);
Audit auditField=field.getAnnotation(Audit.class);
if(!ObjectUtils.isEmpty(deField)) {
defields.put(field.getName(),deField);
if(deField.isKeyField())
cacheDEKeyField.put(className,field.getName());
}
if(!ObjectUtils.isEmpty(auditField)) {
auditfields.put(field.getName(),auditField);
}
}
cacheMap.put(className, result);
cacheList.put(className,list);
cacheKey.put(className,keys);
cacheDEField.put(className,defields);
cacheAuditField.put(className,auditfields);
return result;
}
}
......@@ -97,6 +106,23 @@ public class DEFieldCacheMap {
}
}
/**
* 从缓存中查询审计属性集合
* @param
* @return
*/
public static <T> Hashtable<String,Audit> getAuditFields(Class<T> clazz) {
String className=clazz.getName();
if(className.indexOf("_$")>0)
className=className.substring(0, className.lastIndexOf("_$"));
if(cacheAuditField.containsKey(className))
return cacheAuditField.get(className);
else{
DEFieldCacheMap.getFieldMap(className);
return cacheAuditField.get(className);
}
}
/**
* 从缓存中查询实体对象主键
* @param
......
package cn.ibizlab.util.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.ibizlab.util.domain.IBZDataAudit;
public interface IBZDataAuditMapper extends BaseMapper<IBZDataAudit> {
}
\ No newline at end of file
package cn.ibizlab.util.service;
import cn.ibizlab.util.annotation.Audit;
import cn.ibizlab.util.domain.EntityBase;
import org.springframework.scheduling.annotation.Async;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 实体[DataAudit] 服务对象接口
*/
public interface IBZDataAuditService {
@Async("asyncExecutor")
void createAudit(HttpServletRequest request,EntityBase entity,Object idValue,Map<String, Audit> auditFields);
@Async("asyncExecutor")
void updateAudit(HttpServletRequest request, EntityBase beforeEntity, Object serviceObj, Object idValue, Map<String, Audit> auditFields);
@Async("asyncExecutor")
void removeAudit(HttpServletRequest request,EntityBase entity,Object idValue,Map<String, Audit> auditFields);
}
\ No newline at end of file
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册