MES本地审批共用钉钉审批等配置
This commit is contained in:
@@ -13,6 +13,9 @@ enum Api {
|
||||
// update-begin---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】发起人撤销-----
|
||||
cancel = '/xslmes/approvalHandle/cancel',
|
||||
// update-end---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】发起人撤销-----
|
||||
// update-begin---author:GHT ---date:2026-06-10 for:【IM审批通用化】补发IM审批卡片-----
|
||||
resendCard = '/xslmes/approvalHandle/resendCard',
|
||||
// update-end---author:GHT ---date:2026-06-10 for:【IM审批通用化】补发IM审批卡片-----
|
||||
}
|
||||
|
||||
/** 查看单据全部字段 + 审批进度/历史 */
|
||||
@@ -31,3 +34,9 @@ export const rejectApproval = (params: { instanceId: string; reason: string }) =
|
||||
/** 撤销(仅发起人本人,审批中可撤回,业务单据恢复到发起时状态) */
|
||||
export const cancelApproval = (params: { instanceId: string; reason?: string }) => defHttp.post({ url: Api.cancel, data: params });
|
||||
// update-end---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】发起人撤销-----
|
||||
|
||||
// update-begin---author:GHT ---date:2026-06-10 for:【IM审批通用化】补发IM审批卡片-----
|
||||
/** 补发当前节点 IM 审批卡片(instanceId 与 bizTable+bizDataId 二选一) */
|
||||
export const resendApprovalCard = (params: { instanceId?: string; bizTable?: string; bizDataId?: string }) =>
|
||||
defHttp.post({ url: Api.resendCard, data: params });
|
||||
// update-end---author:GHT ---date:2026-06-10 for:【IM审批通用化】补发IM审批卡片-----
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
<template v-else>
|
||||
<!-- 单条:详情表 -->
|
||||
<template v-if="isSingleItem">
|
||||
<div class="im-biz-record-item">
|
||||
<div class="im-biz-record-item" :class="{ 'im-biz-record-item--ding': isDingStyleCard }">
|
||||
<!-- update-begin---author:GHT ---date:2026-06-10 for:【IM审批通用化】钉钉模板样式卡片头----------- -->
|
||||
<div v-if="isDingStyleCard" class="im-biz-record-ding-header">
|
||||
<span class="im-biz-record-ding-badge">审批</span>
|
||||
<span class="im-biz-record-ding-title">{{ dingCardTitle }}</span>
|
||||
</div>
|
||||
<!-- update-end---author:GHT ---date:2026-06-10 for:【IM审批通用化】钉钉模板样式卡片头----------- -->
|
||||
<div class="im-biz-record-table-wrap">
|
||||
<table class="im-biz-record-table im-biz-record-table--detail">
|
||||
<tbody>
|
||||
@@ -167,6 +173,15 @@
|
||||
const singleItem = computed(() => props.payload.items[0]);
|
||||
const listColumnLabels = computed(() => resolveImBizRecordListColumnLabels(props.payload.items));
|
||||
|
||||
// update-begin---author:GHT ---date:2026-06-10 for:【IM审批通用化】钉钉模板样式卡片-----------
|
||||
const isDingStyleCard = computed(
|
||||
() => props.payload.cardStyle === 'ding' || !!props.payload.templateName,
|
||||
);
|
||||
const dingCardTitle = computed(
|
||||
() => props.payload.templateName || props.payload.pageTitle || '审批单',
|
||||
);
|
||||
// update-end---author:GHT ---date:2026-06-10 for:【IM审批通用化】钉钉模板样式卡片-----------
|
||||
|
||||
// 审批卡片:单条且带审批实例ID
|
||||
const isApprovalCard = computed(() => isSingleItem.value && !!singleItem.value?.instanceId);
|
||||
|
||||
@@ -425,6 +440,50 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
&--ding {
|
||||
.im-biz-record-table-wrap {
|
||||
border-color: #ffe7ba;
|
||||
}
|
||||
|
||||
.im-biz-record-table--detail th {
|
||||
background: #fff7e6;
|
||||
color: #873800;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.im-biz-record-ding-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 6px 6px 0 0;
|
||||
background: linear-gradient(90deg, #fff7e6 0%, #fff 100%);
|
||||
border: 1px solid #ffe7ba;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.im-biz-record-ding-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 36px;
|
||||
padding: 0 6px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
background: #ff6900;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.im-biz-record-ding-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 审批办理按钮栏 */
|
||||
|
||||
@@ -59,21 +59,32 @@
|
||||
placement="right"
|
||||
>
|
||||
<div
|
||||
:class="['conv-item', activeTargetUserId === item.id ? 'active' : '']"
|
||||
:class="[
|
||||
'conv-item',
|
||||
{ active: activeTargetUserId === item.id, 'conv-item--work-notify': isWorkNotifyContact(item) },
|
||||
]"
|
||||
@click="selectMember(item)"
|
||||
>
|
||||
<a-badge :count="shouldShowUnread(item) ? item.unreadCount : 0" :offset="[-2, 2]">
|
||||
<a-avatar :size="leftCollapsed ? 36 : 40" :src="getAvatarUrl(item.avatar)">
|
||||
<a-avatar
|
||||
v-if="isWorkNotifyContact(item)"
|
||||
:size="leftCollapsed ? 36 : 40"
|
||||
:style="{ backgroundColor: '#fa8c16' }"
|
||||
>
|
||||
<Icon icon="ant-design:notification-outlined" />
|
||||
</a-avatar>
|
||||
<a-avatar v-else :size="leftCollapsed ? 36 : 40" :src="getAvatarUrl(item.avatar)">
|
||||
{{ (item.realname || item.username || '?').slice(0, 1) }}
|
||||
</a-avatar>
|
||||
</a-badge>
|
||||
<div v-show="!leftCollapsed" class="conv-meta">
|
||||
<div class="conv-top">
|
||||
<span class="conv-name">{{ item.realname || item.username }}</span>
|
||||
<span v-if="isWorkNotifyContact(item)" class="conv-tag">公众号</span>
|
||||
<span class="conv-time">{{ formatTime(item.lastTime) }}</span>
|
||||
</div>
|
||||
<div class="conv-bottom">
|
||||
<span class="conv-preview">{{ formatConvPreview(item.lastContent) }}</span>
|
||||
<span class="conv-preview">{{ formatConvPreview(item.lastContent, isWorkNotifyContact(item)) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -203,7 +214,9 @@
|
||||
<Icon v-if="embeddedPageContextClickable" icon="ant-design:select-outlined" class="im-page-context-action" />
|
||||
</div>
|
||||
<!--update-end---author:xsl ---date:20260528 for:【IM聊天-OA】弹窗输入框上方展示背后功能页名称------------->
|
||||
<div v-if="isWorkNotifyChat" class="im-work-notify-readonly-tip">工作通知为系统消息通道,仅接收审批等工作消息</div>
|
||||
<ImChatInput
|
||||
v-else
|
||||
v-model="draft"
|
||||
:disabled="!activeConversationId"
|
||||
:sending="sending"
|
||||
@@ -261,6 +274,7 @@
|
||||
import { syncImUnreadFromMembers } from './useImUnread';
|
||||
import {
|
||||
type ImMemberItem,
|
||||
IM_CONTACT_TYPE_WORK_NOTIFY,
|
||||
type ImMessageItem,
|
||||
getCachedMembers,
|
||||
isMembersCacheStale,
|
||||
@@ -539,9 +553,15 @@
|
||||
return parseImBizRecordPayload(content);
|
||||
}
|
||||
|
||||
function formatConvPreview(content?: string) {
|
||||
function isWorkNotifyContact(item?: DeptMemberItem | null) {
|
||||
return item?.contactType === IM_CONTACT_TYPE_WORK_NOTIFY || item?.username === 'im_work_notify';
|
||||
}
|
||||
|
||||
const isWorkNotifyChat = computed(() => isWorkNotifyContact(activeMember.value));
|
||||
|
||||
function formatConvPreview(content?: string, isWorkNotify = false) {
|
||||
if (!content) {
|
||||
return '点击开始聊天';
|
||||
return isWorkNotify ? '暂无系统通知' : '点击开始聊天';
|
||||
}
|
||||
return formatImMessagePreview(content);
|
||||
}
|
||||
@@ -948,7 +968,9 @@
|
||||
function handleOpenCreateGroupModal() {
|
||||
// useModalInner 必须传入 data 才会触发打开回调,否则不会加载成员列表
|
||||
openCreateGroupModal(true, {
|
||||
members: deptMembers.value.filter((item) => item.id !== currentUserId.value),
|
||||
members: deptMembers.value.filter(
|
||||
(item) => item.id !== currentUserId.value && !isWorkNotifyContact(item),
|
||||
),
|
||||
});
|
||||
}
|
||||
//update-end---author:xsl ---date:20260528 for:【IM聊天-OA】发起群聊弹窗需传 data 触发成员加载-----------
|
||||
@@ -1917,6 +1939,36 @@
|
||||
&.active {
|
||||
background: #eef4ff;
|
||||
}
|
||||
|
||||
&.conv-item--work-notify {
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
background: #fff7e6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.conv-tag {
|
||||
flex-shrink: 0;
|
||||
margin-left: 4px;
|
||||
padding: 0 6px;
|
||||
border-radius: 10px;
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.im-work-notify-readonly-tip {
|
||||
padding: 12px 16px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
background: #fafafa;
|
||||
color: #8c8c8c;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.conv-meta {
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { createGroupConversation, fetchDeptMembers } from './im.api';
|
||||
import { getCachedMembers } from './imCache';
|
||||
import { getCachedMembers, IM_CONTACT_TYPE_WORK_NOTIFY } from './imCache';
|
||||
|
||||
defineOptions({ name: 'ImCreateGroupModal' });
|
||||
|
||||
@@ -73,7 +73,13 @@
|
||||
function resolveSelectableMembers(source?: Recordable[]) {
|
||||
const currentUserId = userStore.getUserInfo?.id || '';
|
||||
const list = source?.length ? source : getCachedMembers() || [];
|
||||
return list.filter((item) => item.id && item.id !== currentUserId);
|
||||
return list.filter(
|
||||
(item) =>
|
||||
item.id &&
|
||||
item.id !== currentUserId &&
|
||||
item.contactType !== IM_CONTACT_TYPE_WORK_NOTIFY &&
|
||||
item.username !== 'im_work_notify',
|
||||
);
|
||||
}
|
||||
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data?: { members?: Recordable[] }) => {
|
||||
|
||||
@@ -34,6 +34,12 @@ export interface ImBizRecordPayload {
|
||||
pagePath: string;
|
||||
rowKey: string;
|
||||
items: ImBizRecordItem[];
|
||||
// update-begin---author:GHT ---date:2026-06-10 for:【IM审批通用化】钉钉模板样式卡片扩展-----------
|
||||
/** ding=与钉钉审批模板字段对齐的卡片样式 */
|
||||
cardStyle?: 'ding' | string;
|
||||
templateId?: string;
|
||||
templateName?: string;
|
||||
// update-end---author:GHT ---date:2026-06-10 for:【IM审批通用化】钉钉模板样式卡片扩展-----------
|
||||
}
|
||||
|
||||
/** 构建带跳转链接的业务明细消息体 */
|
||||
|
||||
@@ -8,6 +8,8 @@ import { formatImMessagePreview } from './imMessageUtil';
|
||||
import { syncImUnreadFromMembers } from './useImUnread';
|
||||
import { isImChatPageActive } from './imSession';
|
||||
|
||||
export const IM_CONTACT_TYPE_WORK_NOTIFY = 'work_notify';
|
||||
|
||||
export interface ImMemberItem {
|
||||
id: string;
|
||||
username: string;
|
||||
@@ -18,6 +20,8 @@ export interface ImMemberItem {
|
||||
lastContent?: string;
|
||||
lastTime?: string;
|
||||
unreadCount?: number;
|
||||
/** user=同事 work_notify=工作通知公众号 */
|
||||
contactType?: string;
|
||||
}
|
||||
|
||||
export interface ImMessageItem {
|
||||
|
||||
@@ -19,6 +19,16 @@
|
||||
onClick: handleDetail.bind(null, record),
|
||||
auth: 'xslmes:mes_xsl_approval_record:list',
|
||||
},
|
||||
{
|
||||
label: '补发IM卡片',
|
||||
color: 'warning',
|
||||
ifShow: record.status === '0' && record.channel === 'MES' && !!record.externalInstanceId,
|
||||
popConfirm: {
|
||||
title: '向当前处理人重新发送 IM 审批卡片?',
|
||||
confirm: handleResendCard.bind(null, record),
|
||||
},
|
||||
auth: 'xslmes:mes_xsl_approval_record:list',
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
@@ -34,7 +44,10 @@
|
||||
import MesXslApprovalRecordDetailModal from './components/MesXslApprovalRecordDetailModal.vue';
|
||||
import { columns, searchFormSchema } from './MesXslApprovalRecord.data';
|
||||
import { list, getExportUrl } from './MesXslApprovalRecord.api';
|
||||
import { resendApprovalCard } from '/@/views/approval/flow/approvalHandle.api';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
const { createMessage } = useMessage();
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
const { tableContext, onExportXls } = useListPage({
|
||||
@@ -50,7 +63,7 @@
|
||||
showAdvancedButton: true,
|
||||
},
|
||||
actionColumn: {
|
||||
width: 100,
|
||||
width: 180,
|
||||
fixed: 'right',
|
||||
},
|
||||
},
|
||||
@@ -65,4 +78,13 @@
|
||||
function handleDetail(record: Recordable) {
|
||||
openModal(true, { record });
|
||||
}
|
||||
|
||||
async function handleResendCard(record: Recordable) {
|
||||
try {
|
||||
const msg = await resendApprovalCard({ instanceId: record.externalInstanceId });
|
||||
createMessage.success(msg || '补发成功');
|
||||
} catch (e: any) {
|
||||
createMessage.error(e?.message || '补发失败');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user