审批调整
This commit is contained in:
parent
2d2314c336
commit
dea3be0d4a
@ -145,12 +145,6 @@ export function getGwFlowByIdApi(id: string) {
|
||||
return get(`/api/gw/getGwFlowById?id=${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转办公文
|
||||
*/
|
||||
export function gwTransferApi(params: any) {
|
||||
return post('/api/gw/transfer', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询某人的待办和已办公文
|
||||
@ -158,3 +152,47 @@ export function gwTransferApi(params: any) {
|
||||
export function findUserTodosApi(approveStatus: string, jsId: string, pageNum: number = 1, pageSize: number = 20) {
|
||||
return get('/api/gw/findUserTodos', { approveStatus, jsId, pageNum, pageSize });
|
||||
}
|
||||
|
||||
// ===== 新增:统一的流程接口 =====
|
||||
|
||||
/**
|
||||
* 公文申请
|
||||
*/
|
||||
export function gwSqApi(params: any) {
|
||||
return post('/api/gw/sq', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公文审批
|
||||
*/
|
||||
export function gwSpApi(params: any) {
|
||||
return post('/api/gw/sp', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公文转办
|
||||
*/
|
||||
export function gwTransferApi(params: any) {
|
||||
return post('/api/gw/transfer', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公文终止
|
||||
*/
|
||||
export function gwStopApi(params: any) {
|
||||
return post('/api/gw/stop', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公文重新提交
|
||||
*/
|
||||
export function gwCxtjApi(params: any) {
|
||||
return post('/api/gw/cxtj', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公文协调
|
||||
*/
|
||||
export function gwXtApi(params: any) {
|
||||
return post('/api/gw/xt', params);
|
||||
}
|
||||
|
||||
@ -82,136 +82,9 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 当前处理人 -->
|
||||
<view class="approver-section">
|
||||
<view class="section-title">当前审批人</view>
|
||||
<view class="approver-list">
|
||||
<view
|
||||
v-for="approver in approvers"
|
||||
:key="approver.id"
|
||||
class="approver-item"
|
||||
>
|
||||
<view class="approver-info">
|
||||
<text class="order">{{ approver.order }}</text>
|
||||
<text class="name">{{ approver.userName }}</text>
|
||||
<text class="dept">{{ approver.deptName }}</text>
|
||||
<text class="status" :class="getApproverStatusClass(approver.approveStatus)">
|
||||
{{ getApproverStatusText(approver.approveStatus) }}
|
||||
</text>
|
||||
</view>
|
||||
<!-- 显示审批意见和审批时间 -->
|
||||
<view class="approver-detail" v-if="approver.approveRemark || approver.approveTime">
|
||||
<view class="approval-info" v-if="approver.approveRemark">
|
||||
<text class="info-label">审批意见:</text>
|
||||
<text class="info-value">{{ approver.approveRemark }}</text>
|
||||
</view>
|
||||
<view class="approval-info" v-if="approver.approveTime">
|
||||
<text class="info-label">审批时间:</text>
|
||||
<text class="info-value">{{ formatTime(approver.approveTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 抄送人 -->
|
||||
<view class="cc-section">
|
||||
<view class="section-title">抄送人</view>
|
||||
<view class="cc-list">
|
||||
<view
|
||||
v-for="ccUser in displayedCcUsers"
|
||||
:key="ccUser.id"
|
||||
class="cc-item"
|
||||
>
|
||||
<view class="cc-info">
|
||||
<text class="name">{{ ccUser.userName }}</text>
|
||||
<text class="dept">{{ ccUser.deptName }}</text>
|
||||
<text class="status" :class="getCCStatusClass(ccUser.status)">
|
||||
{{ getCCStatusText(ccUser.status) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 更多按钮 -->
|
||||
<view
|
||||
v-if="ccUsers.length > 2"
|
||||
class="more-button"
|
||||
@click="toggleCcExpanded"
|
||||
>
|
||||
<text class="more-text">
|
||||
{{ ccExpanded ? '收起' : `更多(${ccUsers.length - 2})` }}
|
||||
</text>
|
||||
<text class="more-icon" :class="{ expanded: ccExpanded }">▼</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作记录 -->
|
||||
<view class="log-section">
|
||||
<view class="section-title">操作记录</view>
|
||||
<view class="log-list">
|
||||
<view
|
||||
v-for="log in displayedOperationLogs"
|
||||
:key="log.id"
|
||||
class="log-item"
|
||||
>
|
||||
<view class="log-header">
|
||||
<text class="operator">{{ log.operatorName }}</text>
|
||||
<text class="time">{{ formatTime(log.operationTime) }}</text>
|
||||
</view>
|
||||
<view class="log-content">
|
||||
<text class="content">{{ log.operationContent }}</text>
|
||||
</view>
|
||||
<view class="log-detail" v-if="log.beforeChange || log.afterChange">
|
||||
<u-button
|
||||
text="详情"
|
||||
size="mini"
|
||||
@click="showLogDetail(log)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 更多按钮 -->
|
||||
<view
|
||||
v-if="operationLogs.length > 2"
|
||||
class="more-button"
|
||||
@click="toggleLogExpanded"
|
||||
>
|
||||
<text class="more-text">
|
||||
{{ logExpanded ? '收起' : `更多(${operationLogs.length - 2})` }}
|
||||
</text>
|
||||
<text class="more-icon" :class="{ expanded: logExpanded }">▼</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
<!-- 底部固定按钮 -->
|
||||
<view class="bottom-actions" v-if="canCurrentUserOperate">
|
||||
<!-- 驳回按钮暂时隐藏 -->
|
||||
<!-- <u-button
|
||||
text="驳回"
|
||||
type="error"
|
||||
size="large"
|
||||
@click="handleReject"
|
||||
/> -->
|
||||
<u-button
|
||||
text="转办"
|
||||
type="warning"
|
||||
size="large"
|
||||
@click="handleTransfer"
|
||||
/>
|
||||
<u-button
|
||||
text="同意"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="handleApprove"
|
||||
/>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
<!-- 审批流程 -->
|
||||
<LcglSp :yw-id="gwInfo.id" yw-type="GW"/>
|
||||
|
||||
|
||||
<!-- 操作记录详情弹窗 -->
|
||||
@ -219,7 +92,7 @@
|
||||
<view class="detail-modal">
|
||||
<view class="detail-header">
|
||||
<text class="detail-title">操作详情</text>
|
||||
<u-button text="关闭" @click="showLogDetailModal = false" />
|
||||
<u-button text="关闭" @click="showLogDetailModal = false"/>
|
||||
</view>
|
||||
<view class="detail-content">
|
||||
<view class="detail-item" v-if="currentLog.beforeChange">
|
||||
@ -279,18 +152,32 @@
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<template #bottom>
|
||||
<YwConfirm
|
||||
:spApi="gwSpApi"
|
||||
:stopApi="gwStopApi"
|
||||
:transferApi="gwTransferApi"
|
||||
:params="spParams"
|
||||
:showXt="false"
|
||||
:showReject="true"
|
||||
:showTransfer="true"
|
||||
:showApprove="true"
|
||||
:showReturn="false"
|
||||
:showStop="false"
|
||||
:showXtDk="false"/>
|
||||
</template>
|
||||
</BasicLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
import {ref, onMounted, computed} from "vue";
|
||||
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
||||
import { navigateTo } from "@/utils/uniapp";
|
||||
import {navigateTo} from "@/utils/uniapp";
|
||||
|
||||
import { getGwFlowByIdApi, gwApproveApi } from "@/api/routine/gw";
|
||||
import {getGwFlowByIdApi, gwApproveApi, gwSpApi, gwTransferApi, gwStopApi} from "@/api/routine/gw";
|
||||
import dayjs from "dayjs";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { imagUrl } from "@/utils";
|
||||
import {useUserStore} from "@/store/modules/user";
|
||||
import {imagUrl} from "@/utils";
|
||||
import {
|
||||
isVideo,
|
||||
isImage,
|
||||
@ -300,6 +187,16 @@ import {
|
||||
previewImage as previewImageUtil,
|
||||
downloadFile
|
||||
} from "@/utils/filePreview";
|
||||
import LcglSp from "@/components/LcglSp/index.vue";
|
||||
import YwConfirm from "@/pages/components/YwConfirm/index.vue";
|
||||
import {useDataStore} from "@/store/modules/data";
|
||||
const { setData, getXxts } = useDataStore();
|
||||
const spParams = computed(() => {
|
||||
return{
|
||||
xxtsId: getXxts.id,
|
||||
ywId: gwInfo.value.id
|
||||
}
|
||||
})
|
||||
|
||||
// 类型定义
|
||||
interface GwInfo {
|
||||
@ -365,9 +262,6 @@ interface OperationLog {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 获取页面参数
|
||||
const gwId = ref("");
|
||||
|
||||
@ -379,7 +273,7 @@ const downloadFileName = ref('');
|
||||
const isDownloading = ref(false);
|
||||
|
||||
// 用户store
|
||||
const { getUser, getJs } = useUserStore();
|
||||
const {getUser, getJs} = useUserStore();
|
||||
|
||||
// 数据
|
||||
const gwInfo = ref<GwInfo>({} as GwInfo);
|
||||
@ -517,19 +411,6 @@ const getGwInfo = async () => {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 显示操作日志详情
|
||||
const showLogDetail = (log: OperationLog) => {
|
||||
currentLog.value = log;
|
||||
@ -589,7 +470,7 @@ const handleTransfer = () => {
|
||||
|
||||
// 同时存储到本地存储,作为备用方案
|
||||
uni.setStorageSync('transferData', {
|
||||
xxtsInfo: { id: gwId.value },
|
||||
xxtsInfo: {id: gwId.value},
|
||||
gwInfo: gwInfo.value,
|
||||
approvers: approvers.value,
|
||||
ccUsers: ccUsers.value // 添加抄送人数据
|
||||
@ -874,7 +755,7 @@ const downloadFileAction = (file: FileInfo, event?: Event) => {
|
||||
// 获取原始文件名
|
||||
const originalFileName = getOriginalFileName(file);
|
||||
|
||||
console.log('下载文件:', { finalUrl, originalFileName, file });
|
||||
console.log('下载文件:', {finalUrl, originalFileName, file});
|
||||
|
||||
// 显示下载路径选择弹窗
|
||||
showDownloadPathModal(finalUrl, originalFileName);
|
||||
@ -1077,12 +958,12 @@ const confirmDownload = () => {
|
||||
|
||||
// 检查当前平台
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const { platform } = systemInfo;
|
||||
const {platform} = systemInfo;
|
||||
|
||||
// 备用检测方法
|
||||
const isH5 = platform === 'web' || typeof window !== 'undefined';
|
||||
|
||||
console.log('平台检测:', { platform, systemInfo, isH5 });
|
||||
console.log('平台检测:', {platform, systemInfo, isH5});
|
||||
|
||||
if (isH5) {
|
||||
console.log('使用H5下载方式');
|
||||
@ -1117,7 +998,7 @@ const confirmDownload = () => {
|
||||
// H5环境下的下载方法
|
||||
const downloadForH5 = (url: string, fileName: string) => {
|
||||
try {
|
||||
console.log('H5下载开始:', { url, fileName });
|
||||
console.log('H5下载开始:', {url, fileName});
|
||||
|
||||
// 直接使用强制下载方式,避免打开文件
|
||||
forceDownload(url, fileName);
|
||||
@ -1132,7 +1013,7 @@ const downloadForH5 = (url: string, fileName: string) => {
|
||||
// 强制下载方法
|
||||
const forceDownload = (url: string, fileName: string) => {
|
||||
try {
|
||||
console.log('尝试强制下载:', { url, fileName });
|
||||
console.log('尝试强制下载:', {url, fileName});
|
||||
|
||||
// 方法1: 使用fetch下载文件内容,然后创建blob下载
|
||||
fetch(url, {
|
||||
@ -1196,7 +1077,7 @@ const tryAlternativeDownload = (url: string, fileName: string) => {
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = 'blob';
|
||||
|
||||
xhr.onload = function() {
|
||||
xhr.onload = function () {
|
||||
if (xhr.status === 200) {
|
||||
const blob = xhr.response;
|
||||
const blobUrl = window.URL.createObjectURL(blob);
|
||||
@ -1226,7 +1107,7 @@ const tryAlternativeDownload = (url: string, fileName: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function() {
|
||||
xhr.onerror = function () {
|
||||
console.error('XMLHttpRequest下载失败');
|
||||
console.log('调用手动下载提示');
|
||||
showManualDownloadModal(url, fileName);
|
||||
@ -1503,10 +1384,25 @@ onMounted(() => {
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
|
||||
&.status-draft { background: #f0f0f0; color: #666; }
|
||||
&.status-pending { background: #fff7e6; color: #fa8c16; }
|
||||
&.status-approved { background: #f6ffed; color: #52c41a; }
|
||||
&.status-rejected { background: #fff2f0; color: #ff4d4f; }
|
||||
&.status-draft {
|
||||
background: #f0f0f0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&.status-pending {
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
&.status-approved {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
&.status-rejected {
|
||||
background: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
|
||||
.urgency-tag {
|
||||
@ -1514,9 +1410,20 @@ onMounted(() => {
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
|
||||
&.urgency-normal { background: #f0f0f0; color: #666; }
|
||||
&.urgency-high { background: #fff7e6; color: #fa8c16; }
|
||||
&.urgency-urgent { background: #fff2f0; color: #ff4d4f; }
|
||||
&.urgency-normal {
|
||||
background: #f0f0f0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&.urgency-high {
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
&.urgency-urgent {
|
||||
background: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
|
||||
.file-item {
|
||||
@ -1635,12 +1542,35 @@ onMounted(() => {
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
|
||||
&.status-pending { background: #fff7e6; color: #fa8c16; }
|
||||
&.status-approved { background: #f6ffed; color: #52c41a; }
|
||||
&.status-rejected { background: #fff2f0; color: #ff4d4f; }
|
||||
&.status-skipped { background: #f0f0f0; color: #666; }
|
||||
&.status-unread { background: #fff7e6; color: #fa8c16; }
|
||||
&.status-read { background: #f6ffed; color: #52c41a; }
|
||||
&.status-pending {
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
&.status-approved {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
&.status-rejected {
|
||||
background: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
&.status-skipped {
|
||||
background: #f0f0f0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&.status-unread {
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
&.status-read {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1949,7 +1879,11 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -119,6 +119,7 @@ import { onShow } from "@dcloudio/uni-app";
|
||||
import { navigateTo } from "@/utils/uniapp";
|
||||
import BasicSearch from "@/components/BasicSearch/Search.vue";
|
||||
import { gwFindPageApi, findUserTodosApi } from "@/api/routine/gw";
|
||||
import { gwSqApi, gwSpApi, gwTransferApi, gwStopApi, gwCxtjApi, gwXtApi } from "@/api/routine/gw";
|
||||
import dayjs from "dayjs";
|
||||
import { imagUrl } from "@/utils";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
@ -148,6 +149,7 @@ interface GwListItem {
|
||||
fileFormat?: string;
|
||||
files?: FileInfo[];
|
||||
spZbqd?: string; // 审批人ID(逗号分隔,从审批人表查询)
|
||||
spResult?: string; // 审批结果:A-待处理,B-同意,C-驳回,D-终止
|
||||
tjrtime?: string; // 提交时间
|
||||
[key: string]: any;
|
||||
}
|
||||
@ -278,8 +280,8 @@ const loadUserTodos = async (approveStatus: string, jsId: string) => {
|
||||
loading.value = true;
|
||||
uni.showLoading({ title: '加载中...' });
|
||||
|
||||
// 只调用 findUserTodos 分页接口
|
||||
const response = await findUserTodosApi(approveStatus, jsId, 1, 1000); // 设置较大的pageSize以获取所有数据
|
||||
// 调用 findUserTodos 分页接口,使用合理的分页大小
|
||||
const response = await findUserTodosApi(approveStatus, jsId, 1, 50); // 使用合理的分页大小
|
||||
|
||||
// 检查响应格式 - 根据实际返回的数据结构
|
||||
const result = (response as any).data || response;
|
||||
@ -374,27 +376,58 @@ const getStatusText = (status: string) => {
|
||||
return statusMap[status] || "未知";
|
||||
};
|
||||
|
||||
// 获取按钮文本
|
||||
// 获取按钮文本 - 参考教师请假的逻辑
|
||||
const getButtonText = (item: GwListItem) => {
|
||||
const currentTeacherId = getCurrentTeacherId();
|
||||
const { gwStatus, spZbqd } = item;
|
||||
const { gwStatus, spZbqd, spResult } = item;
|
||||
|
||||
// 如果当前教师ID在spZbqd中,且状态为B(提交),则显示"审批"
|
||||
if (currentTeacherId && spZbqd && gwStatus === 'B') {
|
||||
// 如果是待办状态且当前用户是审批人,显示"审批"
|
||||
if (currentTeacherId && spZbqd && gwStatus === 'B' && activeTab.value === 'pending') {
|
||||
const approverIds = spZbqd.split(',').map(id => id.trim());
|
||||
if (approverIds.includes(currentTeacherId)) {
|
||||
return '审批';
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是已办状态,根据审批结果显示不同按钮
|
||||
if (activeTab.value === 'approved') {
|
||||
if (spResult === 'B') {
|
||||
return '已同意';
|
||||
} else if (spResult === 'C') {
|
||||
return '已驳回';
|
||||
} else if (spResult === 'D') {
|
||||
return '已终止';
|
||||
}
|
||||
}
|
||||
|
||||
// 其他情况显示"详情"
|
||||
return '详情';
|
||||
};
|
||||
|
||||
// 获取按钮样式类
|
||||
// 获取按钮样式类 - 参考教师请假的样式
|
||||
const getButtonClass = (item: GwListItem) => {
|
||||
const buttonText = getButtonText(item);
|
||||
return buttonText === '审批' ? 'action-button-approve' : 'action-button-detail';
|
||||
const currentTeacherId = getCurrentTeacherId();
|
||||
const { gwStatus, spZbqd, spResult } = item;
|
||||
|
||||
// 审批按钮样式
|
||||
if (buttonText === '审批') {
|
||||
return 'action-button-approve';
|
||||
}
|
||||
|
||||
// 已办状态按钮样式
|
||||
if (activeTab.value === 'approved') {
|
||||
if (spResult === 'B') {
|
||||
return 'action-button-approved'; // 已同意
|
||||
} else if (spResult === 'C') {
|
||||
return 'action-button-rejected'; // 已驳回
|
||||
} else if (spResult === 'D') {
|
||||
return 'action-button-stopped'; // 已终止
|
||||
}
|
||||
}
|
||||
|
||||
// 默认详情按钮样式
|
||||
return 'action-button-detail';
|
||||
};
|
||||
|
||||
// 紧急程度相关函数已删除
|
||||
@ -877,7 +910,10 @@ onUnmounted(() => {
|
||||
|
||||
// 按钮样式,与状态标签大小相同
|
||||
.action-button-approve,
|
||||
.action-button-detail {
|
||||
.action-button-detail,
|
||||
.action-button-approved,
|
||||
.action-button-rejected,
|
||||
.action-button-stopped {
|
||||
padding: 4px 8px !important;
|
||||
border-radius: 12px !important;
|
||||
font-size: 12px !important;
|
||||
@ -901,6 +937,24 @@ onUnmounted(() => {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.action-button-approved {
|
||||
background: linear-gradient(135deg, #66bb6a 0%, #4caf50 100%) !important;
|
||||
color: white !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.action-button-rejected {
|
||||
background: linear-gradient(135deg, #ef5350 0%, #e53935 100%) !important;
|
||||
color: white !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.action-button-stopped {
|
||||
background: linear-gradient(135deg, #9e9e9e 0%, #757575 100%) !important;
|
||||
color: white !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
// 响应式优化
|
||||
@media (max-width: 375px) {
|
||||
.query-component {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user