自定义页面树和tab接口对接
This commit is contained in:
parent
34d7ab154a
commit
2d1c756985
|
|
@ -7,7 +7,7 @@ import {
|
|||
* @param {Object} params [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
export const getTabInfo = (moduleName, params = {}) => WeaTools.callApi(`/api/hrm/${moduleName}/getTabInfo?is_multilang_set=true`, 'GET', params)
|
||||
export const getTabInfo = (moduleName, params = {}) => WeaTools.callApi('/api/bs/hrmorganization/fieldDefined/getTabInfo', 'GET', params)
|
||||
|
||||
export const getFieldDefinedInfo = (moduleName, params = {}) => WeaTools.callApi(`/api/hrm/${moduleName}/getFieldDefinedInfo?is_multilang_set=true`, 'GET', params)
|
||||
|
||||
|
|
@ -15,11 +15,34 @@ export const saveFieldDefinedInfo = (moduleName, params = {}) => WeaTools.callAp
|
|||
|
||||
export const removeFieldDefinedInfo = (moduleName, params = {}) => WeaTools.callApi(`/api/hrm/${moduleName}/del`, 'POST', params)
|
||||
|
||||
export const saveGroupInfo = (moduleName, params = {}) => WeaTools.callApi(`/api/hrm/${moduleName}/saveGroup`, 'POST', params)
|
||||
export const saveGroupInfo = (moduleName,params) => {
|
||||
return fetch('/api/bs/hrmorganization/fieldDefined/saveTitle', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(params)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const changeTypeInfo = (moduleName,params) => {
|
||||
return fetch(`/api/bs/hrmorganization/fieldDefined/${moduleName}/changeTree`, {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(params)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const removeGroupInfo = (moduleName, params = {}) => WeaTools.callApi(`/api/hrm/${moduleName}/delGroup`, 'POST', params)
|
||||
|
||||
export const getTree = (params = {}) => WeaTools.callApi(`/api/hrm/resourcefielddefined/getTree`, 'GET', params)
|
||||
export const getTree = (moduleName,params = {}) => WeaTools.callApi(`/api/bs/hrmorganization/fieldDefined/${moduleName}/getTree`, 'GET', params)
|
||||
|
||||
export const saveTree = (params = {}) => WeaTools.callApi(`/api/hrm/resourcefielddefined/saveTree`, 'POST', params)
|
||||
|
||||
|
|
|
|||
|
|
@ -56,13 +56,15 @@ export default class FieldDefined extends Component {
|
|||
let moduleName, logSmallType;
|
||||
if (moduleType === 'subCompany') {
|
||||
moduleName = 'subcompanyfielddefined';
|
||||
logSmallType = 'HRM_ENGINE_SUBCOMPANYFIELDDEFINED';
|
||||
//logSmallType = 'HRM_ENGINE_SUBCOMPANYFIELDDEFINED';
|
||||
} else if (moduleType === 'department') {
|
||||
moduleName = 'departmentfielddefined';
|
||||
logSmallType = 'HRM_ENGINE_DEPARTMENTFIELDDEFINED';
|
||||
} else {
|
||||
//logSmallType = 'HRM_ENGINE_DEPARTMENTFIELDDEFINED';
|
||||
} else if(moduleType === 'job') {
|
||||
moduleName = 'jobfielddefined';
|
||||
}else {
|
||||
moduleName = 'resourcefielddefined';
|
||||
logSmallType = 'HRM_ENGINE_RESOURCEFIELDDEFINED';
|
||||
//logSmallType = 'HRM_ENGINE_RESOURCEFIELDDEFINED';
|
||||
}
|
||||
// let callbackFunc = () => initData(false, true, moduleName);
|
||||
// if (moduleType === 'resource')
|
||||
|
|
|
|||
|
|
@ -843,6 +843,7 @@ export const i18n = {
|
|||
button: {
|
||||
back: () => getLabel(1290, '返回'),
|
||||
createType: () => getLabel(30131, '新建类型'),
|
||||
editTypeInfo: () => getLabel(32732, '编辑类型'),
|
||||
|
||||
batchOpen: () => getLabel(534249, '批量解锁'),
|
||||
collect: () => getLabel(28111, '收藏'),
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ export class CompanyExtendStore {
|
|||
save = () => {
|
||||
if (this.loading)
|
||||
return;
|
||||
this.loading = true;
|
||||
this.form.validateForm().then(f => {
|
||||
if (f.isValid) {
|
||||
this.loading = true;
|
||||
if (this.personalEditTables) {
|
||||
const targetDatas = this.tableInfo[this.detailSelectedKey].tabinfo.datas,
|
||||
isPass = (targetDatas.length > 0) ? this.personalEditTables.refs.edit.doRequiredCheck().pass : true
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* @Author: 程亮
|
||||
* @Date: 2022-06-09 10:16:00
|
||||
* @LastEditTime: 2022-06-13 16:55:34
|
||||
* @LastEditTime: 2022-06-15 18:47:39
|
||||
* @Description:
|
||||
* @FilePath: /trunk/src4js/pc4mobx/organization/stores/fieldDefined.js
|
||||
*/
|
||||
|
|
@ -67,7 +67,9 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
}, {
|
||||
comType: 'button',
|
||||
type: 'primary',
|
||||
onClickHandle: () => this.editType(),
|
||||
onClickHandle: () => this.editTypeInfo(true, {
|
||||
name: this.selectedTreeNodeInfo.name,
|
||||
}),
|
||||
label: i18n.button.createType,
|
||||
icon: this.menuIconCollection.create
|
||||
}, {
|
||||
|
|
@ -504,7 +506,7 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
"items": [{
|
||||
"colSpan": 2,
|
||||
"conditionType": "INPUT",
|
||||
"domkey": ["typeName"],
|
||||
"domkey": ["name"],
|
||||
"fieldcol": 12,
|
||||
"isQuickSearch": false,
|
||||
"label": i18n.label.typeName,
|
||||
|
|
@ -513,59 +515,6 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
"rules": "required|string",
|
||||
"value": "",
|
||||
"viewAttr": 3,
|
||||
}, {
|
||||
"belong": "PC",
|
||||
"checkbox": false,
|
||||
"checkboxValue": false,
|
||||
"colSpan": 2,
|
||||
"conditionType": "SELECT",
|
||||
"dateGroup": false,
|
||||
"defaultDisplayInBar": false,
|
||||
"detailtype": 3,
|
||||
"domkey": [
|
||||
"tableType"
|
||||
],
|
||||
"entSearch": false,
|
||||
"fieldcol": 16,
|
||||
"hasBorder": false,
|
||||
"helpfulTipProps": {},
|
||||
"hide": false,
|
||||
"isBase64": false,
|
||||
"isQuickSearch": false,
|
||||
"label": "新增到",
|
||||
"labelcol": 6,
|
||||
"length": 0,
|
||||
"maxFilesNumber": 0,
|
||||
"maxUploadSize": 0,
|
||||
"multiSelection": false,
|
||||
"multiple": false,
|
||||
"options": [
|
||||
{
|
||||
"disabled": false,
|
||||
"key": "0",
|
||||
"selected": false,
|
||||
"showname": "主表",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"disabled": false,
|
||||
"key": "1",
|
||||
"selected": false,
|
||||
"showname": "明细表",
|
||||
"visible": true
|
||||
}
|
||||
],
|
||||
"precision": 0,
|
||||
"secretLimit": false,
|
||||
"showOrder": 0,
|
||||
"showTime": false,
|
||||
"stringLength": 0,
|
||||
"supportCancel": false,
|
||||
"tipPosition": "bottom",
|
||||
"value": "0",
|
||||
"valueList": [],
|
||||
"rules": "required|string",
|
||||
"viewAttr": 3
|
||||
}],
|
||||
"defaultshow": true
|
||||
}]
|
||||
|
|
@ -821,7 +770,7 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
this.dialogParams.childInfoSetting.visible && this.doSaveChildInfoSetting();
|
||||
}
|
||||
|
||||
@action editGroup = (group, moveToGroup = false) => {
|
||||
@action("新建分组") editGroup = (group, moveToGroup = false) => {
|
||||
this.moveToGroup = moveToGroup;
|
||||
this.editGroupInfoFormFields.map(f => {
|
||||
if (typeof (f.title) == 'function')
|
||||
|
|
@ -851,7 +800,9 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
this.setDialogVisible('editGroupInfo', true, dialogTitle);
|
||||
}
|
||||
|
||||
@action editType = () => {
|
||||
isCreateTypeInfo = false;
|
||||
@action("新增或创建类型") editTypeInfo = (create = true, data = {}) => {
|
||||
this.isCreateTypeInfo = create;
|
||||
this.editTypeInfoFormFields.map(f => {
|
||||
if (typeof (f.title) == 'function')
|
||||
f.title = f.title();
|
||||
|
|
@ -862,17 +813,20 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
})
|
||||
})
|
||||
let fields = [...this.editTypeInfoFormFields],
|
||||
dialogTitle = '';
|
||||
dialogTitle = create ? i18n.button.createType() : i18n.button.editTypeInfo();
|
||||
this.setFormData('typeInfoFrom', fields);
|
||||
// this.formTarget.typeInfoFrom.updateFields({
|
||||
// typeName: { value: '' }
|
||||
// });
|
||||
// this.opId = null;
|
||||
dialogTitle = i18n.button.createType();
|
||||
if (!create) {
|
||||
this.formTarget.typeInfoFrom.updateFields({
|
||||
name: { value: data.name }
|
||||
});
|
||||
}else {
|
||||
this.selectedTreeNodeInfo.domid = null;
|
||||
}
|
||||
|
||||
this.setDialogVisible('editTypeInfo', true, dialogTitle);
|
||||
}
|
||||
|
||||
@action doGroupSetting = () => {
|
||||
@action("分组维护") doGroupSetting = () => {
|
||||
this.tableEditConfig.groupSetting.datas.length = 0;
|
||||
let arr = [];
|
||||
this.tabRecord.map(tabInfo => {
|
||||
|
|
@ -920,36 +874,27 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
}
|
||||
|
||||
|
||||
@action doSaveTypeInfo = () => {
|
||||
@action("保存类型") doSaveTypeInfo = () => {
|
||||
this.formTarget.typeInfoFrom.validateForm().then(f => {
|
||||
if (f.isValid) {
|
||||
let record = {
|
||||
...this.formTarget.typeInfoFrom.getFormParams(),
|
||||
}
|
||||
debugger
|
||||
let params = {
|
||||
data: JSON.stringify({
|
||||
record: record
|
||||
})
|
||||
... this.formTarget.typeInfoFrom.getFormParams(),
|
||||
id: this.selectedTreeNodeInfo.domid
|
||||
}
|
||||
// api.saveTypeInfo(this.moduleName, params).then(data => {
|
||||
// if (data.status === '1') {
|
||||
// this.setDialogVisible('editGroupInfo', false, '');
|
||||
// if (this.moveToGroup) {
|
||||
// const ids = data.groupid.split(',');
|
||||
// this.changeGroup(null, ids[ids.length - 1]);
|
||||
// } else {
|
||||
// //if (this.moduleName.indexOf('resource') >= 0)
|
||||
// this.getTabInfoByTreeNode();
|
||||
// // else
|
||||
// // this.initData(this.opId == null);
|
||||
// message.success(i18n.message.saveSuccess());
|
||||
// }
|
||||
// } else
|
||||
// message.error(data.message);
|
||||
// }, error => {
|
||||
// message.error(i18n.message.actionError());
|
||||
// });
|
||||
this.getTree()
|
||||
api.changeTypeInfo(this.moduleName, params).then(response => {
|
||||
return response.json()
|
||||
}).then(data => {
|
||||
if (data.code === 200) {
|
||||
this.setDialogVisible('editTypeInfo', false, '');
|
||||
this.getTree()
|
||||
message.success(i18n.message.saveSuccess());
|
||||
} else {
|
||||
message.warning(data.msg);
|
||||
}
|
||||
}).catch(error => {
|
||||
message.warning(error.msg);
|
||||
})
|
||||
} else {
|
||||
f.showErrors();
|
||||
this.showError = new Date().getTime();
|
||||
|
|
@ -957,7 +902,7 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
});
|
||||
}
|
||||
|
||||
doSaveGroupInfo = () => {
|
||||
@action("分组保存") doSaveGroupInfo = () => {
|
||||
this.formTarget.groupInfoFrom.validateForm().then(f => {
|
||||
if (f.isValid) {
|
||||
let record = {
|
||||
|
|
@ -972,51 +917,33 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
this.showError = new Date().getTime();
|
||||
return;
|
||||
}
|
||||
let found = false,
|
||||
records = [];
|
||||
this.opId != null && Object.assign(record, {
|
||||
id: this.opId,
|
||||
isShow: this.activeTabInfo.tabInfo.isShow
|
||||
});
|
||||
this.tabConfig.tabs.map(tabInfo => {
|
||||
if (tabInfo.groupid === this.opId) {
|
||||
found = true;
|
||||
records.push(record)
|
||||
} else {
|
||||
records.push({
|
||||
id: tabInfo.groupid,
|
||||
isShow: tabInfo.isShow,
|
||||
groupName: tabInfo.title
|
||||
})
|
||||
}
|
||||
});
|
||||
!found && records.push(record);
|
||||
let params = {
|
||||
data: JSON.stringify({
|
||||
records: records
|
||||
})
|
||||
...this.formTarget.groupInfoFrom.getFormParams(),
|
||||
isShow: 1
|
||||
}
|
||||
|
||||
if (this.selectedTreeNodeInfo != null)
|
||||
params.groupType = this.selectedTreeNodeInfo.key
|
||||
|
||||
api.saveGroupInfo(this.moduleName, params).then(data => {
|
||||
if (data.status === '1') {
|
||||
api.saveGroupInfo(this.moduleName, params).then(response => {
|
||||
return response.json()
|
||||
}).then(data => {
|
||||
if (data.code === 200) {
|
||||
this.setDialogVisible('editGroupInfo', false, '');
|
||||
if (this.moveToGroup) {
|
||||
const ids = data.groupid.split(',');
|
||||
const ids = data.data.groupid.split(',');
|
||||
this.changeGroup(null, ids[ids.length - 1]);
|
||||
} else {
|
||||
//if (this.moduleName.indexOf('resource') >= 0)
|
||||
this.getTabInfoByTreeNode();
|
||||
// else
|
||||
// this.initData(this.opId == null);
|
||||
message.success(i18n.message.saveSuccess());
|
||||
}
|
||||
} else
|
||||
message.error(data.message);
|
||||
}, error => {
|
||||
message.error(i18n.message.actionError());
|
||||
});
|
||||
} else {
|
||||
message.warning(data.msg);
|
||||
}
|
||||
}).catch(error => {
|
||||
message.warning(error.msg);
|
||||
})
|
||||
|
||||
} else {
|
||||
f.showErrors();
|
||||
this.showError = new Date().getTime();
|
||||
|
|
@ -1341,7 +1268,8 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
dataObj.groupType = this.selectedTreeNodeInfo.key;
|
||||
params.groupType = this.selectedTreeNodeInfo.key;
|
||||
}
|
||||
params.data = JSON.stringify(dataObj);
|
||||
params.data = dataObj;
|
||||
|
||||
api.saveGroupInfo(this.moduleName, params).then(data => {
|
||||
if (data.status === '1') {
|
||||
this.setDialogVisible('groupInfoSetting', false, '');
|
||||
|
|
@ -1355,6 +1283,7 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
}, error => {
|
||||
message.error(i18n.message.actionError());
|
||||
});
|
||||
|
||||
} else {
|
||||
message.error(i18n.confirm.groupNameExist());
|
||||
}
|
||||
|
|
@ -1446,27 +1375,21 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
this.selectedTreeNodeInfo = null;
|
||||
this.dropdownSelectedKey = '1';
|
||||
this.moduleName = module;
|
||||
// let columns = cloneDeep(this.fieldDefColumns())
|
||||
// columns.splice(1, 1);
|
||||
// columns[1].width = '65%';
|
||||
// this.tableEditConfig.fieldDef.columns = this.getColumns();
|
||||
this.treeConfig.treeExpandKeys.length = 0;
|
||||
api.getTree().then(data => {
|
||||
if (data.status === '1') {
|
||||
api.getTree(this.moduleName).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.containerInitFinished = {
|
||||
...this.containerInitFinished,
|
||||
init: true
|
||||
}
|
||||
|
||||
// this.setTableEditColTitle();
|
||||
if (data.treejson.length > 0) {
|
||||
this.treeConfig.data = data.treejson;
|
||||
this.treeConfig.selectedKeys = [data.treejson[0].key];
|
||||
this.selectedTreeNodeInfo = data.treejson[0];
|
||||
if (res.data.length > 0) {
|
||||
this.treeConfig.data = res.data;
|
||||
this.treeConfig.selectedKeys = [res.data[0].key];
|
||||
this.selectedTreeNodeInfo = res.data[0];
|
||||
this.getTabInfoByTreeNode(null, true);
|
||||
}
|
||||
} else {
|
||||
message.error(data.message);
|
||||
message.error(res.msg);
|
||||
}
|
||||
}, error => { })
|
||||
}
|
||||
|
|
@ -1474,9 +1397,9 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
getTree = (callback) => {
|
||||
this.treeConfig.data.length = 0;
|
||||
this.refreshTree = new Date().getTime();
|
||||
api.getTree().then(data => {
|
||||
if (data.status === '1') {
|
||||
this.treeConfig.data = data.treejson;
|
||||
api.getTree(this.moduleName).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.treeConfig.data = res.data;
|
||||
this.treeConfig.data.map(p => {
|
||||
if (p.domid === this.treeConfig.selectedKeys[0])
|
||||
this.selectedTreeNodeInfo = p;
|
||||
|
|
@ -1487,7 +1410,7 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
})
|
||||
callback && callback();
|
||||
} else {
|
||||
message.error(data.message);
|
||||
message.error(res.msg);
|
||||
}
|
||||
this.refreshTree = new Date().getTime();
|
||||
}, error => { })
|
||||
|
|
@ -1497,38 +1420,46 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
if (!this.selectedTreeNodeInfo.hasGroup) {
|
||||
t.topButtonDef.splice(1, 3);
|
||||
}
|
||||
if (this.selectedTreeNodeInfo.addChild) {
|
||||
t.topButtonDef.push({
|
||||
comType: 'button',
|
||||
type: 'primary',
|
||||
onClickHandle: () => this.editTypeInfo(false, {
|
||||
name: this.selectedTreeNodeInfo.name,
|
||||
}),
|
||||
label: i18n.button.editTypeInfo(),
|
||||
icon: this.menuIconCollection.setting
|
||||
})
|
||||
if (this.selectedTreeNodeInfo.addChild) { //非子节点
|
||||
this.tableEditConfig.childInfoSetting.showTitle = true;
|
||||
this.tableEditConfig.childInfoSetting.showAdd = true;
|
||||
this.tableEditConfig.childInfoSetting.showDelete = true;
|
||||
// this.selectedTreeNodeInfo.domid != '-1' && t.topButtonDef.push({
|
||||
// comType: 'button',
|
||||
// type: 'primary',
|
||||
// onClickHandle: this.doChildInfoSetting,
|
||||
// label: i18n.button.childInfoMaintain(),
|
||||
// icon: this.menuIconCollection.setting,
|
||||
// checkAction: 'childInfoOperability'
|
||||
// });
|
||||
let domid = this.selectedTreeNodeInfo.domid;
|
||||
//非基本类型()
|
||||
(domid != '-1' && domid != '-2' && domid != '-3' && domid != '-4') && t.topButtonDef.push({
|
||||
comType: 'button',
|
||||
type: 'primary',
|
||||
onClickHandle: this.doChildInfoSetting,
|
||||
label: i18n.button.childInfoMaintain(),
|
||||
icon: this.menuIconCollection.setting,
|
||||
checkAction: 'childInfoOperability'
|
||||
}) && t.topButtonDef.push({
|
||||
comType: 'button',
|
||||
type: 'primary',
|
||||
onClickHandle: this.removeTypeInfo,
|
||||
label: i18n.button.delete(),
|
||||
icon: this.menuIconCollection.setting
|
||||
});
|
||||
} else {
|
||||
this.tableEditConfig.childInfoSetting.showTitle = false;
|
||||
this.tableEditConfig.childInfoSetting.showAdd = false;
|
||||
this.tableEditConfig.childInfoSetting.showDelete = false;
|
||||
this.selectedTreeNodeInfo.domid != '-1' && t.topButtonDef.push({
|
||||
t.topButtonDef.push({
|
||||
comType: 'button',
|
||||
type: 'primary',
|
||||
onClickHandle: () => this.createChildInfo(false, {
|
||||
name: this.selectedTreeNodeInfo.name,
|
||||
multiName: this.selectedTreeNodeInfo.multiName
|
||||
}),
|
||||
label: i18n.button.editChildInfo(),
|
||||
icon: this.menuIconCollection.setting
|
||||
}) && t.topButtonDef.push({
|
||||
comType: 'button',
|
||||
type: 'primary',
|
||||
onClickHandle: this.removeChildInfo,
|
||||
onClickHandle: this.removeTypeInfo,
|
||||
label: i18n.button.delete(),
|
||||
icon: this.menuIconCollection.setting
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if (this.selectedTreeNodeInfo.domid === '-1' || this.selectedTreeNodeInfo.addChild) {
|
||||
|
|
@ -1553,12 +1484,12 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
@action getTabInfoByTreeNode = (create = false, init = false, isLeaf) => {
|
||||
api.getTabInfo(this.moduleName, {
|
||||
groupType: this.treeConfig.selectedKeys[0]
|
||||
}).then(data => {
|
||||
if (data.status === '1') {
|
||||
this._groupInfoOperability = data.tabs.length === 0;
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
this._groupInfoOperability = res.data.tabs.length === 0;
|
||||
let tabArr = [];
|
||||
this.tabRecord = data.tabs;
|
||||
data.tabs && data.tabs.map((tabInfo, index) => {
|
||||
this.tabRecord = res.data.tabs;
|
||||
res.data.tabs && res.data.tabs.map((tabInfo, index) => {
|
||||
let t = cloneDeep(this.tabDef);
|
||||
this.setBtn(t);
|
||||
tabArr.push({
|
||||
|
|
@ -1616,6 +1547,9 @@ export class FieldDefinedStore extends HrmBaseStore {
|
|||
this.setDialogVisible('createChildInfo', true, dialogTitle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@action doSaveChildInfo = () => {
|
||||
this.formTarget.childInfoForm.validateForm().then(f => {
|
||||
if (f.isValid) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue