yxk-20260803

改善提案-权限控制
根据菜单路由区分 mine/dept/institute:我的提案:仅本人数据,可新增、编辑草稿、删除草稿、发起流程。
部门提案:仅本人有效业务部门内已发起提案,只读查看。
全所提案:全所已发起提案;处理中记录可删除流程。

[ImprovementProposalController.java]对列表和导出强制应用范围过滤;部门范围只识别 org_type='2'、org_category='2' 的关联部门。草稿编辑、删除、发起流程也增加了创建人校验。
删除流程改用独立权限:improvementproposal:improvement_proposal:withdrawProcess。
新增全所/部门范围权限:deptView、instituteView。
This commit is contained in:
ye1023
2026-08-03 14:50:31 +08:00
parent 115a8aabe4
commit 9175cff789
2 changed files with 39 additions and 50 deletions
@@ -327,41 +327,4 @@ export const superQuerySchema = {
improvementMethod: {title: '改善方法及措施',order: 10,view: 'textarea', type: 'string',},
finalAward: {title: '最终奖项',order: 14,view: 'text', type: 'string',},
bpmStatus: {title: '流程状态',order: 15,view: 'text', type: 'string',},
//子表高级查询
improvementDeptScore: {
title: '部门评议评分表',
view: 'table',
fields: {
mainId: {title: '改善提案主表ID',order: 0,view: 'text', type: 'string',},
processTaskId: {title: '流程任务ID',order: 1,view: 'text', type: 'string',},
scorerId: {title: '评委ID',order: 2,view: 'text', type: 'string',},
scorerName: {title: '评委姓名',order: 3,view: 'text', type: 'string',},
scoreStatus: {title: '评分状态:pending/completed',order: 4,view: 'text', type: 'string',},
safetyScore: {title: '安全得分',order: 5,view: 'number', type: 'number',},
qualityScore: {title: '质量得分',order: 6,view: 'number', type: 'number',},
efficiencyScore: {title: '效率得分',order: 7,view: 'number', type: 'number',},
costScore: {title: '成本得分',order: 8,view: 'number', type: 'number',},
effectScore: {title: '改善效果平均得分',order: 9,view: 'number', type: 'number',},
promotionScore: {title: '可推广度得分',order: 10,view: 'number', type: 'number',},
originalityScore: {title: '独创性得分',order: 11,view: 'number', type: 'number',},
effortScore: {title: '努力度得分',order: 12,view: 'number', type: 'number',},
totalScore: {title: '加权总分',order: 13,view: 'number', type: 'number',},
scoreOpinion: {title: '评分意见',order: 14,view: 'textarea', type: 'string',},
scoreTime: {title: '评分时间',order: 15,view: 'datetime', type: 'string',},
}
},
improvementInstituteVote: {
title: '所级评议投票表',
view: 'table',
fields: {
mainId: {title: '改善提案主表ID',order: 0,view: 'text', type: 'string',},
processTaskId: {title: '流程任务ID',order: 1,view: 'text', type: 'string',},
voterId: {title: '投票人ID',order: 2,view: 'text', type: 'string',},
voterName: {title: '投票人姓名',order: 3,view: 'text', type: 'string',},
voteStatus: {title: '投票状态:pending/voted',order: 4,view: 'text', type: 'string',},
voteResult: {title: '投票结果:agree/disagree',order: 5,view: 'text', type: 'string',},
voteOpinion: {title: '投票意见',order: 6,view: 'textarea', type: 'string',},
voteTime: {title: '投票时间',order: 7,view: 'datetime', type: 'string',},
}
},
};
@@ -16,7 +16,7 @@
<JDictSelectTag v-model:value="queryParam.proposalCategory" dictCode="proposal_category" placeholder="请选择提案类别" allow-clear @change="reload" />
</a-form-item>
</a-col>
<a-col v-if="toggleSearchStatus" :lg="6">
<a-col v-if="toggleSearchStatus && isInstituteScope" :lg="6">
<a-form-item name="bpmStatus">
<template #label><span title="流程状态">流程状态</span></template>
<JDictSelectTag v-model:value="queryParam.bpmStatus" dictCode="bpm_status" placeholder="请选择流程状态" allow-clear @change="reload" />
@@ -50,13 +50,13 @@
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<BasicTable @register="registerTable" :rowSelection="isMineScope ? rowSelection : undefined">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" v-auth="'improvementproposal:improvement_proposal:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" v-auth="'improvementproposal:improvement_proposal:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" v-auth="'improvementproposal:improvement_proposal:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-button v-if="isMineScope" type="primary" v-auth="'improvementproposal:improvement_proposal:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button v-if="isMineScope" type="primary" v-auth="'improvementproposal:improvement_proposal:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button v-if="isMineScope" type="primary" v-auth="'improvementproposal:improvement_proposal:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-dropdown v-if="isMineScope && selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
@@ -88,7 +88,8 @@
</template>
<script lang="ts" name="improvementproposal-improvementProposal" setup>
import {ref, reactive} from 'vue';
import {computed, ref, reactive, watch} from 'vue';
import {useRoute} from 'vue-router';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage'
import {useModal} from '/@/components/Modal';
@@ -101,11 +102,28 @@
import SzSelectDept from '/@/components/Form/src/jeecg/components/SzSelectDept.vue';
const [registerBpmModal, { openModal: bpmPicModal }] = useModal();
const route = useRoute();
const formRef = ref();
const queryParam = reactive<any>({});
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerModal, {openModal}] = useModal();
/** 三个菜单复用一个页面,通过固定路由后缀决定服务端数据范围。 */
function resolveProposalScope(path: string) {
if (path.endsWith('/deptProposalList')) {
return 'dept';
}
if (path.endsWith('/instituteProposalList')) {
return 'institute';
}
return 'mine';
}
const proposalScope = ref(resolveProposalScope(route.path));
const isMineScope = computed(() => proposalScope.value === 'mine');
const isInstituteScope = computed(() => proposalScope.value === 'institute');
queryParam.proposalScope = proposalScope.value;
//注册table数据
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
@@ -119,7 +137,7 @@
fixed:'right'
},
beforeFetch: async (params) => {
return Object.assign(params, queryParam);
return Object.assign(params, queryParam, {proposalScope: proposalScope.value});
},
},
exportConfig: {
@@ -135,6 +153,14 @@
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
// 相同组件在三个动态菜单间复用时,主动刷新查询范围,避免保留上一个菜单的数据。
watch(() => route.path, (path) => {
proposalScope.value = resolveProposalScope(path);
queryParam.proposalScope = proposalScope.value;
selectedRowKeys.value = [];
reload();
});
// 高级查询配置
const superQueryConfig = reactive(superQuerySchema);
@@ -204,7 +230,7 @@
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'improvementproposal:improvement_proposal:edit',
ifShow: isDraft(record),
ifShow: isMineScope.value && isDraft(record),
}
];
return actions;
@@ -219,7 +245,7 @@
onClick: handleDetail.bind(null, record),
}
];
if (isDraft(record)) {
if (isMineScope.value && isDraft(record)) {
dropDownAction.push({
label: '删除',
popConfirm: {
@@ -229,7 +255,7 @@
auth: 'improvementproposal:improvement_proposal:delete'
});
}
if (isProcessing(record)) {
if (isInstituteScope.value && isProcessing(record)) {
dropDownAction.push({
label: '删除流程',
popConfirm: {
@@ -237,7 +263,7 @@
confirm: handleWithdrawProcess.bind(null, record),
placement: 'topLeft',
},
auth: 'improvementproposal:improvement_proposal:delete'
auth: 'improvementproposal:improvement_proposal:withdrawProcess'
});
}
dropDownAction.push(
@@ -247,7 +273,7 @@
ifShow: !!record.bpmStatus && record.bpmStatus !== '1',
}
);
if(isDraft(record)){
if(isMineScope.value && isDraft(record)){
dropDownAction.push({
label: '发起流程',
popConfirm: {