feat(oa/crm): 实现出差申请交流反馈权限控制

- 添加用户角色列表管理功能
- 实现基于角色的交流过程与反馈字段可见性控制
- 集成tripCommView角色权限验证机制
- 支持申请人本人查看反馈内容
- 更新表格列显示逻辑增加角色权限判断
- 移除固定用户ID访问限制改为角色化控制
- 添加行程明细列表和创建人字段类型定义
- 注释掉无权限用户的反馈填写功能入口
dev
Yangk 2 days ago
parent cdc76abc52
commit 51e1d51f27

@ -117,6 +117,16 @@ export interface BusinessTripApplyVO {
* ID
*/
ossId: string | number;
/**
*
*/
createBy?: string | number;
/**
*
*/
exchangeFeedback?: string;
}
export interface BusinessTripApplyForm extends BaseEntity {
@ -268,6 +278,16 @@ export interface BusinessTripApplyForm extends BaseEntity {
* ID
*/
copyUserIds?: string | string[];
/**
*
*/
exchangeFeedback?: string;
/**
*
*/
crmBusinessTripDetailsList?: any[];
}
export interface BusinessTripApplyQuery extends PageQuery {

@ -432,30 +432,15 @@ const submitFormData = ref<StartProcessBo>({
});
const taskVariables = ref<Record<string, any>>({});
// ID
const BUSINESS_DIRECTION_LEADER_MAP: Record<number, string> = {
1: '1985254821554475009',
2: '1985258519835889666',
3: '1985251968270127105',
4: '1985257496048226305',
5: '1985254145713688578'
};
//
//
const userRoles = ref<string[]>([]);
// ""
const hasTripCommViewRole = computed(() => userRoles.value?.some((role) => role === 'tripCommView'));
//
const canViewFeedback = computed(() => {
if (hasTripCommViewRole.value) return true;
const currentUserId = String(useUserStore().userId);
// 1.
if (form.value.applicantId && currentUserId === String(form.value.applicantId)) return true;
// 2. userList
const fixedNames = ['陈海军', '张东辉'];
const fixedIds = fixedNames
.map((name) => userList.value.find((u: any) => u.nickName === name))
.filter(Boolean)
.map((u: any) => String(u.userId));
if (fixedIds.includes(currentUserId)) return true;
// 3.
const bd = Number(form.value.businessDirection);
if (bd && BUSINESS_DIRECTION_LEADER_MAP[bd] && currentUserId === BUSINESS_DIRECTION_LEADER_MAP[bd]) return true;
return false;
});
@ -591,19 +576,25 @@ onMounted(async () => {
const customerRes = await getCrmCustomerInfoList({});
customerList.value = customerRes.data || [];
//
if (!id) {
try {
const infoRes = await getInfo();
//
try {
const infoRes = await getInfo();
userRoles.value = infoRes.data?.roles || [];
//
if (!id) {
if (infoRes.data?.user) {
form.value.applicantId = infoRes.data.user.userId;
form.value.applicantName = infoRes.data.user.nickName;
form.value.deptId = infoRes.data.user.deptId;
form.value.deptName = infoRes.data.user.deptName;
}
} catch (e) {
console.error('获取用户信息失败', e);
}
} catch (e) {
console.error('获取用户信息失败', e);
userRoles.value = [];
}
if (!id) {
// index tripType
if (routeParams.value.tripType) {
form.value.tripType = routeParams.value.tripType;
@ -635,7 +626,7 @@ onMounted(async () => {
confirmCopyIds.push(String(matchedUser.userId));
}
});
// ID SpelRuleComponent.java
const BUSINESS_DIRECTION_TO_USERNAME: Record<number, string> = {
1: '1985254821554475009',
@ -648,7 +639,7 @@ onMounted(async () => {
if (bd && BUSINESS_DIRECTION_TO_USERNAME[bd]) {
confirmCopyIds.push(BUSINESS_DIRECTION_TO_USERNAME[bd]);
}
//
form.value.copyUserIds = Array.from(new Set([...(form.value.copyUserIds || []), ...confirmCopyIds]));
//
@ -728,7 +719,7 @@ const projectInfoSelectCallBack = (data: ProjectInfoVO[]) => {
}
form.value.variables.approverId = String(selectedProject.managerId);
handleApproverSelectChange(String(selectedProject.managerId));
proxy?.$modal.msgSuccess('已关联项目经理作为下一步审批人');
// proxy?.$modal.msgSuccess('');
}
}
}
@ -948,7 +939,7 @@ const approvalVerifyOpen = async () => {
if (!isValid) return;
if (!aggregateDetailsToForm()) return;
buttonLoading.value = true;
try {
if (form.value.tripId) {

@ -120,7 +120,14 @@
</el-table-column>
<el-table-column label="交流目的" align="center" prop="exchangePurpose" width="150" show-overflow-tooltip v-if="columns[17].visible" />
<el-table-column label="会议/展会名称" align="center" prop="meetingName" width="150" show-overflow-tooltip v-if="columns[19].visible" />
<el-table-column label="交流过程与反馈" align="center" prop="exchangeFeedback" width="200" show-overflow-tooltip v-if="columns[20].visible">
<el-table-column
label="交流过程与反馈"
align="center"
prop="exchangeFeedback"
width="200"
show-overflow-tooltip
v-if="columns[20].visible && hasTripCommViewRole"
>
<template #default="scope">
<span v-if="canViewRowFeedback(scope.row)">{{ scope.row.exchangeFeedback }}</span>
<span v-else style="color: #c0c4cc">-</span>
@ -146,19 +153,19 @@
<el-tooltip content="查看详情" placement="top" v-if="scope.row.flowStatus !== 'draft' && scope.row.flowStatus">
<el-button link type="info" icon="DocumentChecked" @click="handleView(scope.row)"></el-button>
</el-tooltip>
<el-tooltip
content="填写反馈"
placement="top"
v-if="scope.row.tripStatus === '3' && (scope.row.tripType === '2' || scope.row.tripType === '3') && canViewRowFeedback(scope.row)"
>
<el-button
link
type="success"
icon="ChatDotRound"
@click="handleFeedback(scope.row)"
v-hasPermi="['oa/crm:businessTripApply:edit']"
></el-button>
</el-tooltip>
<!-- <el-tooltip-->
<!-- content="填写反馈"-->
<!-- placement="top"-->
<!-- v-if="scope.row.tripStatus === '3' && (scope.row.tripType === '2' || scope.row.tripType === '3') && canViewRowFeedback(scope.row)"-->
<!-- >-->
<!-- <el-button-->
<!-- link-->
<!-- type="success"-->
<!-- icon="ChatDotRound"-->
<!-- @click="handleFeedback(scope.row)"-->
<!-- v-hasPermi="['oa/crm:businessTripApply:edit']"-->
<!-- ></el-button>-->
<!-- </el-tooltip>-->
<!-- <el-tooltip content="删除" placement="top">-->
<!-- <el-button-->
<!-- link-->
@ -204,8 +211,21 @@ import { UserQuery, UserVO } from '@/api/system/user/types';
import { allListDept, listDept } from '@/api/system/dept';
import { DeptVO } from '@/api/system/dept/types';
import { useUserStore } from '@/store/modules/user';
import { getInfo } from '@/api/login';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userRoles = ref<string[]>([]);
// ""
const hasTripCommViewRole = computed(() => userRoles.value?.some((role) => role === 'tripCommView'));
//
const canViewRowFeedback = (row: BusinessTripApplyVO): boolean => {
if (hasTripCommViewRole.value) return true;
const currentUserId = String(useUserStore().userId);
if (row.createBy && currentUserId === String(row.createBy)) return true;
return false;
};
const { trip_status, trip_type, business_direction } = toRefs<any>(proxy?.useDict('trip_status', 'trip_type', 'business_direction'));
const businessTripApplyList = ref<BusinessTripApplyVO[]>([]);
@ -219,32 +239,6 @@ const router = useRouter();
const userList = ref<UserVO[]>([]);
const deptList = ref<DeptVO[]>([]);
// ID
const BUSINESS_DIRECTION_LEADER_MAP: Record<number, string> = {
1: '1985254821554475009',
2: '1985258519835889666',
3: '1985251968270127105',
4: '1985257496048226305',
5: '1985254145713688578'
};
//
const canViewRowFeedback = (row: BusinessTripApplyVO): boolean => {
const currentUserId = String(useUserStore().userId);
// 1.
if (row.applicantId && currentUserId === String(row.applicantId)) return true;
// 2.
const fixedIds = ['陈海军', '张东辉']
.map(name => userList.value.find((u: any) => u.nickName === name))
.filter(Boolean)
.map((u: any) => String(u.userId));
if (fixedIds.includes(currentUserId)) return true;
// 3.
const bd = Number(row.businessDirection);
if (bd && BUSINESS_DIRECTION_LEADER_MAP[bd] && currentUserId === BUSINESS_DIRECTION_LEADER_MAP[bd]) return true;
return false;
};
const queryFormRef = ref<ElFormInstance>();
//
@ -380,6 +374,13 @@ const handleExport = () => {
};
onMounted(async () => {
//
try {
const infoRes = await getInfo();
userRoles.value = infoRes.data?.roles || [];
} catch (e) {
userRoles.value = [];
}
//
const userQuery = ref<UserQuery>();
const userRes = await getUserList(userQuery.value);
@ -391,10 +392,6 @@ onMounted(async () => {
getList();
});
onActivated(() => {
getList();
});
// ============ ============
const feedbackDialogVisible = ref(false);
const feedbackLoading = ref(false);
@ -414,21 +411,21 @@ const feedbackRules = {
exchangeFeedback: [{ required: true, message: '请填写交流过程与反馈', trigger: 'blur' }]
};
/** 填写反馈按钮操作 */
const handleFeedback = (row: BusinessTripApplyVO) => {
feedbackForm.value = {
tripId: row.tripId,
applyCode: row.applyCode,
tripType: row.tripType,
applicantId: row.applicantId,
tripLocation: row.tripLocation,
startTime: row.startTime,
endTime: row.endTime,
durationDays: row.durationDays,
exchangeFeedback: row.exchangeFeedback || ''
};
feedbackDialogVisible.value = true;
};
// /** */
// const handleFeedback = (row: BusinessTripApplyVO) => {
// feedbackForm.value = {
// tripId: row.tripId,
// applyCode: row.applyCode,
// tripType: row.tripType,
// applicantId: row.applicantId,
// tripLocation: row.tripLocation,
// startTime: row.startTime,
// endTime: row.endTime,
// durationDays: row.durationDays,
// exchangeFeedback: row.exchangeFeedback || ''
// };
// feedbackDialogVisible.value = true;
// };
/** 提交反馈 */
const submitFeedback = async () => {

Loading…
Cancel
Save