修改办公模块预览组件,屏蔽通过条件下依然可以文件上传问题
This commit is contained in:
@@ -4,14 +4,13 @@
|
||||
<div slot="header" class="card-header">
|
||||
<span>{{ bizTitle }}</span>
|
||||
<div class="actions">
|
||||
<el-button size="mini" icon="el-icon-arrow-left" @click="$router.back()">返回</el-button>
|
||||
<el-button v-if="!preview" size="mini" icon="el-icon-arrow-left" @click="$router.back()">返回</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="loadDetail">刷新</el-button>
|
||||
|
||||
<!-- 审批操作按钮 -->
|
||||
<el-button v-if="canApprove" type="success" size="mini" :loading="actionLoading" @click="handleApprove">
|
||||
<el-button v-if="!preview && canApprove" type="success" size="mini" :loading="actionLoading" @click="handleApprove">
|
||||
通过
|
||||
</el-button>
|
||||
<el-button v-if="canApprove" type="danger" size="mini" :loading="actionLoading" @click="handleReject">
|
||||
<el-button v-if="!preview && canApprove" type="danger" size="mini" :loading="actionLoading" @click="handleReject">
|
||||
驳回
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -54,20 +53,21 @@
|
||||
<ProjectInfo :info="detail" />
|
||||
</el-card>
|
||||
|
||||
<div class="block-title">审批操作</div>
|
||||
<el-card class="inner-card" shadow="never">
|
||||
<div class="hint-text">系统将自动识别你在该单据上的“当前待办任务”。若你不是当前办理人,将不会显示办理按钮。</div>
|
||||
<div v-if="currentTask" class="btn-row">
|
||||
<el-input v-model="actionRemark" type="textarea" :rows="3" placeholder="填写审批意见(可选)" />
|
||||
<div class="btn-row mt10">
|
||||
<el-button type="success" v-if="canApprove" :loading="actionSubmitting"
|
||||
@click="submitTaskAction('approve')">通过</el-button>
|
||||
<el-button type="danger" v-if="canApprove" :loading="actionSubmitting"
|
||||
@click="submitTaskAction('reject')">驳回</el-button>
|
||||
<div v-if="!preview">
|
||||
<div class="block-title">审批操作</div>
|
||||
<el-card class="inner-card" shadow="never">
|
||||
<div v-if="currentTask" class="btn-row">
|
||||
<el-input v-model="actionRemark" type="textarea" :rows="3" placeholder="填写审批意见(可选)" />
|
||||
<div class="btn-row mt10">
|
||||
<el-button type="success" v-if="canApprove" :loading="actionSubmitting"
|
||||
@click="submitTaskAction('approve')">通过</el-button>
|
||||
<el-button type="danger" v-if="canApprove" :loading="actionSubmitting"
|
||||
@click="submitTaskAction('reject')">驳回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty">当前无待办任务(可能已处理完成,或你不是当前审批人)</div>
|
||||
</el-card>
|
||||
<div v-else class="empty">当前无待办任务(可能已处理完成,或你不是当前审批人)</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="report-card" shadow="never">
|
||||
@@ -75,7 +75,7 @@
|
||||
<span>操作汇报</span>
|
||||
</div>
|
||||
|
||||
<div class="comment-form">
|
||||
<div v-if="!preview" class="comment-form">
|
||||
<editor v-model="commentForm.commentContent" placeholder="填写操作汇报(可选)" />
|
||||
<file-upload v-model="commentForm.attachments" />
|
||||
<div class="form-actions">
|
||||
@@ -89,7 +89,7 @@
|
||||
<div class="comment-meta">
|
||||
<span class="comment-operator">{{ item.createByName }}</span>
|
||||
<span class="comment-time">{{ item.createTime }}</span>
|
||||
<el-button v-if="isSelf(item)" type="danger" size="mini" @click="handleDeleteComment(item.commentId)"
|
||||
<el-button v-if="!preview && isSelf(item)" type="danger" size="mini" @click="handleDeleteComment(item.commentId)"
|
||||
:loading="buttonLoading">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,7 +132,8 @@ export default {
|
||||
name: 'BizDetailContainer',
|
||||
props: {
|
||||
bizId: { type: String, required: true },
|
||||
bizType: { type: String, required: true }
|
||||
bizType: { type: String, required: true },
|
||||
preview: { type: Boolean, default: false }
|
||||
},
|
||||
components: {
|
||||
FilePreview,
|
||||
@@ -414,7 +415,7 @@ export default {
|
||||
async exportComment () {
|
||||
try {
|
||||
this.buttonLoading = true
|
||||
const res = await addFlowComment({
|
||||
await addFlowComment({
|
||||
instId: this.flowInstance.instId,
|
||||
commentContent: this.commentForm.commentContent,
|
||||
attachments: this.commentForm.attachments
|
||||
|
||||
@@ -1,81 +1,68 @@
|
||||
<template>
|
||||
<div class="hrm-page">
|
||||
<div class="flow-task-layout">
|
||||
<!-- 左:任务列表 -->
|
||||
<el-card class="metal-panel left" shadow="hover">
|
||||
<el-card class="metal-panel left" shadow="never">
|
||||
<div slot="header" class="panel-header">
|
||||
<div class="header-title">
|
||||
<span>审批历史</span>
|
||||
<span class="sub">面向办理人:只看已完成,不可操作</span>
|
||||
</div>
|
||||
<div class="actions-inline">
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="fetchList">刷新</el-button>
|
||||
<el-button size="mini" plain icon="el-icon-refresh" @click="fetchList">刷新</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table :data="list" v-loading="loading" height="680" stripe highlight-current-row @row-click="openDetail">
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<el-table
|
||||
:data="list"
|
||||
v-loading="loading"
|
||||
height="680"
|
||||
stripe
|
||||
highlight-current-row
|
||||
@row-click="openDetail"
|
||||
>
|
||||
<el-table-column label="业务" min-width="140">
|
||||
<template slot-scope="scope">
|
||||
<div class="biz-cell">
|
||||
<span class="biz-type">{{ bizTypeText(scope.row.bizType) }}</span>
|
||||
<span class="biz-title">{{ scope.row.title || scope.row.remark }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审批状态" min-width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="statusType(scope.row.status)" size="mini">{{ statusText(scope.row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="业务" min-width="120">
|
||||
<el-table-column label="审批时间" min-width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="mini" type="info">{{ bizTypeText(scope.row.bizType) }}</el-tag>
|
||||
<span class="muted" v-if="scope.row.bizId"> #{{ scope.row.bizId }}</span>
|
||||
<span>{{ formatDate(scope.row.updateTime || scope.row.createTime) || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" prop="remark" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button link type="primary" @click="openDetail(scope.row)">查看详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<!-- 右:详情区 -->
|
||||
<el-card class="metal-panel right" shadow="hover">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>任务详情</span>
|
||||
<div class="actions-inline">
|
||||
<el-button size="mini" icon="el-icon-document-copy" :disabled="!detailTask"
|
||||
@click="copyTaskInfo">复制关键信息</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-card class="metal-panel right" shadow="never">
|
||||
<div slot="header" class="panel-header"></div>
|
||||
|
||||
<div v-if="!detailTask" class="placeholder">
|
||||
<div class="p-title">请在左侧选择一条任务</div>
|
||||
<div class="p-sub">将展示业务信息、表单字段、流转历史</div>
|
||||
<div class="p-title">请在左侧选择一条审批记录</div>
|
||||
<div class="p-sub">右侧将展示表单内容和流转历史</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="detail-wrap">
|
||||
<div class="detail-summary">
|
||||
<div class="ds-left">
|
||||
<div class="ds-title">{{ bizTypeText(detailTask.bizType) }} · 任务 #{{ detailTask.taskId }}</div>
|
||||
<div class="ds-title">{{ bizTypeText(detailTask.bizType) }} · {{ detailTask.title || '审批详情' }}</div>
|
||||
<div class="ds-sub">
|
||||
<el-tag size="mini" :type="statusType(detailTask.status)">{{ statusText(detailTask.status) }}</el-tag>
|
||||
<span class="muted">实例 {{ detailTask.instId }} · 节点 {{ detailTask.nodeId }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ds-right">
|
||||
<div class="ds-item">
|
||||
<div class="k">办理人</div>
|
||||
<div class="v">{{ formatUser(detailTask.assigneeUserId, 'userId') }}</div>
|
||||
</div>
|
||||
<div class="ds-item">
|
||||
<div class="k">到期</div>
|
||||
<div class="v">{{ formatDate(detailTask.expireTime) || '-' }}</div>
|
||||
<span class="muted">审批时间 {{ formatDate(detailTask.updateTime || detailTask.createTime) || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tabs value="form">
|
||||
<el-tab-pane label="表单数据" name="form">
|
||||
<LeaveDetail v-if="detailTask && detailTask.bizType === 'leave'" :biz-id="detailTask.bizId" :embedded="true" />
|
||||
<TravelDetail v-else-if="detailTask && detailTask.bizType === 'travel'" :biz-id="detailTask.bizId" :embedded="true" />
|
||||
<SealDetail v-else-if="detailTask && detailTask.bizType === 'seal'" :biz-id="detailTask.bizId" :embedded="true" />
|
||||
<ReimburseDetail v-else-if="detailTask && detailTask.bizType === 'reimburse'" :biz-id="detailTask.bizId" :embedded="true" />
|
||||
<LeaveDetail v-if="detailTask && detailTask.bizType === 'leave'" :biz-id="detailTask.bizId" :embedded="true" :preview="true" />
|
||||
<TravelDetail v-else-if="detailTask && detailTask.bizType === 'travel'" :biz-id="detailTask.bizId" :embedded="true" :preview="true" />
|
||||
<SealDetail v-else-if="detailTask && detailTask.bizType === 'seal'" :biz-id="detailTask.bizId" :embedded="true" :preview="true" />
|
||||
<ReimburseDetail v-else-if="detailTask && detailTask.bizType === 'reimburse'" :biz-id="detailTask.bizId" :embedded="true" :preview="true" />
|
||||
|
||||
<div v-else>
|
||||
<el-table :data="formData" v-loading="formLoading" size="mini" height="260">
|
||||
@@ -88,7 +75,12 @@
|
||||
|
||||
<el-tab-pane label="流转历史" name="history">
|
||||
<el-timeline v-loading="actionLoading" v-if="actionList.length">
|
||||
<el-timeline-item v-for="(a, idx) in actionList" :key="idx" :timestamp="formatDate(a.createTime)" :type="actionTagType(a.action)">
|
||||
<el-timeline-item
|
||||
v-for="(a, idx) in actionList"
|
||||
:key="idx"
|
||||
:timestamp="formatDate(a.createTime)"
|
||||
:type="actionTagType(a.action)"
|
||||
>
|
||||
<div class="timeline-row">
|
||||
<div class="t-main">
|
||||
<span class="t-action">{{ actionText(a.action) }}</span>
|
||||
@@ -109,10 +101,7 @@
|
||||
|
||||
<script>
|
||||
import { listHistoryFlowTask, listFlowAction, listFlowFormData } from '@/api/hrm/flow'
|
||||
|
||||
import { listByIds } from '@/api/system/oss'
|
||||
import { listUser } from '@/api/system/user'
|
||||
|
||||
import LeaveDetail from '@/views/hrm/requests/leaveDetail.vue'
|
||||
import ReimburseDetail from '@/views/hrm/requests/reimburseDetail.vue'
|
||||
import SealDetail from '@/views/hrm/requests/sealDetail.vue'
|
||||
@@ -126,7 +115,7 @@ export default {
|
||||
return {
|
||||
query: { status: undefined, pageNum: 1, pageSize: 50 },
|
||||
list: [],
|
||||
total: 0,
|
||||
total: 0,
|
||||
loading: false,
|
||||
detailTask: null,
|
||||
actionList: [],
|
||||
@@ -148,56 +137,34 @@ export default {
|
||||
actionText(action) { const map = { submit: '提交', approve: '通过', reject: '驳回', withdraw: '撤回', cancel: '撤销', stamp: '盖章', transfer: '转发' }; return map[action] || action || '-' },
|
||||
actionTagType(action) { const map = { submit: 'primary', approve: 'success', reject: 'danger', withdraw: 'info', cancel: 'info', stamp: 'primary', transfer: 'warning' }; return map[action] || 'info' },
|
||||
async loadAllUsers() { try { const res = await listUser({ pageNum: 1, pageSize: 1000 }); this.allUsers = res.rows || [] } catch (e) { this.allUsers = [] } },
|
||||
formatUser(userId, fieldName) { if (!userId) return '-'; const user = this.allUsers.find(u => u[fieldName] === userId); return user ? `${user.nickName || user.userName}` : `ID:${userId}` },
|
||||
|
||||
formatUser(userId, fieldName) { if (!userId) return '-'; const user = this.allUsers.find(u => u[fieldName] === userId); return user ? `${user.nickName || user.userName}` : '-' },
|
||||
|
||||
fetchList() {
|
||||
this.loading = true
|
||||
|
||||
listHistoryFlowTask(this.query).then(res => {
|
||||
|
||||
this.list = res.rows || []
|
||||
this.total = res.total || 0
|
||||
|
||||
if (!this.detailTask && this.list.length) {
|
||||
this.openDetail(this.list[0])
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
if (!this.detailTask && this.list.length) this.openDetail(this.list[0])
|
||||
}).finally(() => { this.loading = false })
|
||||
},
|
||||
|
||||
async openDetail(row) {
|
||||
|
||||
openDetail(row) {
|
||||
if (!row) return
|
||||
this.detailTask = row
|
||||
this.loadActions(row)
|
||||
this.loadFormData(row)
|
||||
},
|
||||
|
||||
loadActions(row) {
|
||||
if (!row || !row.instId) return;
|
||||
this.actionLoading = true;
|
||||
listFlowAction({ instId: row.instId }).then(res => {
|
||||
this.actionList = res.rows || []
|
||||
}).finally(() => {
|
||||
this.actionLoading = false
|
||||
})
|
||||
|
||||
loadActions(row) {
|
||||
if (!row || !row.instId) return
|
||||
this.actionLoading = true
|
||||
listFlowAction({ instId: row.instId }).then(res => { this.actionList = res.rows || [] }).finally(() => { this.actionLoading = false })
|
||||
},
|
||||
|
||||
loadFormData(row) {
|
||||
if (!row || !row.instId) return;
|
||||
this.formLoading = true;
|
||||
listFlowFormData({ instId: row.instId }).then(res => {
|
||||
this.formData = res.rows || []
|
||||
}).finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
copyTaskInfo() {
|
||||
if (!this.detailTask) return;
|
||||
const t = this.detailTask;
|
||||
const text = `任务ID:${t.taskId}\n实例:${t.instId}\n业务:${t.bizType}${t.bizId ? `#${t.bizId}` : ''}\n节点:${t.nodeId}\n状态:${t.status}`;
|
||||
navigator.clipboard.writeText(text).then(() => this.$message.success('已复制'))
|
||||
|
||||
loadFormData(row) {
|
||||
if (!row || !row.instId) return
|
||||
this.formLoading = true
|
||||
listFlowFormData({ instId: row.instId }).then(res => { this.formData = res.rows || [] }).finally(() => { this.formLoading = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -205,32 +172,38 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hrm-page {
|
||||
padding: 16px 20px 32px;
|
||||
background: #f8f9fb;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
.flow-task-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 520px 1fr;
|
||||
gap: 14px;
|
||||
gap: 12px;
|
||||
align-items: start;
|
||||
}
|
||||
.metal-panel { border: 1px solid #d7d9df; border-radius: 12px; background: #fff; }
|
||||
.panel-header { display: flex; justify-content: space-between; align-items: center; font-weight: 800; color: #2b2f36; }
|
||||
.metal-panel {
|
||||
border: 1px solid rgba(215, 217, 223, 0.55);
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
box-shadow: none;
|
||||
}
|
||||
.panel-header { display: flex; justify-content: space-between; align-items: center; font-weight: 700; color: #2b2f36; padding: 0; min-height: 0; }
|
||||
.header-title { display: flex; flex-direction: column; }
|
||||
.header-title .sub { font-size: 12px; color: #8a8f99; margin-top: 2px; font-weight: 500; }
|
||||
.actions-inline { display: flex; gap: 8px; align-items: center; }
|
||||
.biz-cell { display: flex; flex-direction: column; gap: 2px; }
|
||||
.biz-type { font-size: 12px; color: #8a8f99; }
|
||||
.biz-title { font-weight: 500; color: #2b2f36; line-height: 1.2; }
|
||||
.muted { color: #8a8f99; font-size: 12px; }
|
||||
.placeholder { padding: 18px 14px; border: 1px dashed #e6e8ed; border-radius: 12px; background: #fafbfc; }
|
||||
.p-title { font-weight: 900; color: #2b2f36; }
|
||||
.placeholder { padding: 18px 14px; border: 1px dashed #eef0f3; border-radius: 8px; background: #fff; }
|
||||
.p-title { font-weight: 700; color: #2b2f36; }
|
||||
.p-sub { margin-top: 6px; color: #8a8f99; font-size: 13px; }
|
||||
.detail-wrap { padding-right: 4px; }
|
||||
.detail-summary { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; padding: 12px; border: 1px solid #e6e8ed; border-radius: 12px; background: #fff; }
|
||||
.ds-title { font-weight: 900; color: #2b2f36; }
|
||||
.detail-wrap { padding-right: 2px; }
|
||||
.detail-summary { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; padding: 12px; border: 1px solid rgba(230, 232, 237, 0.65); border-radius: 8px; background: #fff; }
|
||||
.ds-title { font-weight: 700; color: #2b2f36; }
|
||||
.ds-sub { margin-top: 6px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
||||
.ds-right { display: flex; gap: 16px; }
|
||||
.ds-item .k { font-size: 12px; color: #8a8f99; }
|
||||
.ds-item .v { margin-top: 2px; font-weight: 800; color: #2b2f36; }
|
||||
/* removed extra right-side summary metadata */
|
||||
.empty { padding: 12px; color: #8a8f99; }
|
||||
.timeline-row .t-main { font-weight: 600; color: #2b2f36; }
|
||||
.timeline-row .t-remark { margin-top: 4px; color: #606266; font-size: 13px; }
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BizDetailContainer :bizId="currentBizId" bizType="appropriation">
|
||||
<BizDetailContainer :bizId="currentBizId" bizType="appropriation" :preview="preview">
|
||||
<template slot-scope="{ detail }">
|
||||
<div>
|
||||
<!-- 拨款金额信息 -->
|
||||
@@ -59,7 +59,8 @@ export default {
|
||||
name: 'AppropriationDetail',
|
||||
props: {
|
||||
bizId: { type: [String, Number], default: null },
|
||||
embedded: { type: Boolean, default: false }
|
||||
embedded: { type: Boolean, default: false },
|
||||
preview: { type: Boolean, default: false }
|
||||
},
|
||||
components: {
|
||||
FilePreview,
|
||||
@@ -114,8 +115,7 @@ export default {
|
||||
return this.detail.status === 'pending' && (this.currentTask?.assigneeUserName === this.$store.getters.name || this.currentTask?.assigneeUserId === this.$store.getters.id)
|
||||
},
|
||||
canWithdraw () {
|
||||
return false;
|
||||
return this.detail.status === 'pending' && this.detail.createBy === this.$store.getters.name
|
||||
return false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BizDetailContainer :bizId="currentBizId" bizType="leave">
|
||||
<BizDetailContainer :bizId="currentBizId" bizType="leave" :preview="preview">
|
||||
<template slot-scope="{ detail }">
|
||||
<div>
|
||||
<!-- 请假日期信息 -->
|
||||
@@ -50,7 +50,8 @@ export default {
|
||||
name: 'LeaveDetail',
|
||||
props: {
|
||||
bizId: { type: [String, Number], default: null },
|
||||
embedded: { type: Boolean, default: false }
|
||||
embedded: { type: Boolean, default: false },
|
||||
preview: { type: Boolean, default: false }
|
||||
},
|
||||
components: {
|
||||
FilePreview,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BizDetailContainer :bizId="currentBizId" bizType="reimburse">
|
||||
<BizDetailContainer :bizId="currentBizId" bizType="reimburse" :preview="preview">
|
||||
<template slot-scope="{ detail }">
|
||||
<div>
|
||||
<!-- 报销金额信息 -->
|
||||
@@ -47,7 +47,8 @@ export default {
|
||||
name: 'ReimburseDetail',
|
||||
props: {
|
||||
bizId: { type: [String, Number], default: null },
|
||||
embedded: { type: Boolean, default: false }
|
||||
embedded: { type: Boolean, default: false },
|
||||
preview: { type: Boolean, default: false }
|
||||
},
|
||||
components: {
|
||||
BizDetailContainer,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BizDetailContainer :bizId="currentBizId" bizType="travel">
|
||||
<BizDetailContainer :bizId="currentBizId" bizType="travel" :preview="preview">
|
||||
<template slot-scope="{ detail }">
|
||||
<div>
|
||||
<!-- 出差时间与行程 -->
|
||||
@@ -46,7 +46,8 @@ export default {
|
||||
name: 'TravelDetail',
|
||||
props: {
|
||||
bizId: { type: [String, Number], default: '' },
|
||||
embedded: { type: Boolean, default: false }
|
||||
embedded: { type: Boolean, default: false },
|
||||
preview: { type: Boolean, default: false }
|
||||
},
|
||||
components: {
|
||||
BizDetailContainer,
|
||||
|
||||
Reference in New Issue
Block a user