feat(approval): 员工端待办/已办与通过驳回撤回 (#20)
- 审批中心三个 tab 接入待办/已办接口,支持状态+关键词筛选与下拉刷新 - 详情页新增通过(意见可选)、驳回(意见必填)、撤回(二次确认) - 驳回/撤回后提供修改并重新提交入口,按钮按 permissions 显隐
This commit is contained in:
@@ -4,7 +4,8 @@ import type {
|
|||||||
ApprovalCompletionForm,
|
ApprovalCompletionForm,
|
||||||
ApprovalInstance,
|
ApprovalInstance,
|
||||||
ApprovalItem,
|
ApprovalItem,
|
||||||
ApprovalMineParam
|
ApprovalMineParam,
|
||||||
|
ApprovalTaskListParam
|
||||||
} from '../model';
|
} from '../model';
|
||||||
import { THINK_API_URL } from '@/config/setting';
|
import { THINK_API_URL } from '@/config/setting';
|
||||||
|
|
||||||
@@ -61,3 +62,31 @@ export async function pageMine(params: ApprovalMineParam) {
|
|||||||
}
|
}
|
||||||
return Promise.reject(new Error(res.data.message));
|
return Promise.reject(new Error(res.data.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 我的待办
|
||||||
|
*/
|
||||||
|
export async function pageTodo(params: ApprovalTaskListParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<ApprovalItem>>>(
|
||||||
|
THINK_API_URL + '/approval/todo/page',
|
||||||
|
{ params }
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 我的已办
|
||||||
|
*/
|
||||||
|
export async function pageDone(params: ApprovalTaskListParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<ApprovalItem>>>(
|
||||||
|
THINK_API_URL + '/approval/done/page',
|
||||||
|
{ params }
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|||||||
@@ -136,6 +136,21 @@ export interface ApprovalMineParam extends PageParam {
|
|||||||
docType?: string;
|
docType?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办/已办查询参数
|
||||||
|
*/
|
||||||
|
export interface ApprovalTaskListParam extends PageParam {
|
||||||
|
status?: string;
|
||||||
|
docType?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务动作参数(通过/驳回)
|
||||||
|
*/
|
||||||
|
export interface ApprovalTaskActionParam {
|
||||||
|
opinion?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组织
|
* 组织
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { ApiResult } from '@/api';
|
import type { ApiResult } from '@/api';
|
||||||
|
import type { ApprovalInstance } from '../model';
|
||||||
import { THINK_API_URL } from '@/config/setting';
|
import { THINK_API_URL } from '@/config/setting';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,3 +15,44 @@ export async function getTodoCount() {
|
|||||||
}
|
}
|
||||||
return Promise.reject(new Error(res.data.message));
|
return Promise.reject(new Error(res.data.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过(意见可选)
|
||||||
|
*/
|
||||||
|
export async function approveTask(id: number, opinion?: string) {
|
||||||
|
const res = await request.post<ApiResult<ApprovalInstance>>(
|
||||||
|
THINK_API_URL + '/approval/task/' + id + '/approve',
|
||||||
|
{ opinion }
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驳回(意见必填)
|
||||||
|
*/
|
||||||
|
export async function rejectTask(id: number, opinion: string) {
|
||||||
|
const res = await request.post<ApiResult<ApprovalInstance>>(
|
||||||
|
THINK_API_URL + '/approval/task/' + id + '/reject',
|
||||||
|
{ opinion }
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回
|
||||||
|
*/
|
||||||
|
export async function withdrawInstance(id: number) {
|
||||||
|
const res = await request.post<ApiResult<ApprovalInstance>>(
|
||||||
|
THINK_API_URL + '/approval/instance/' + id + '/withdraw'
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|||||||
@@ -109,13 +109,35 @@
|
|||||||
<view v-if="detail.records.length === 0" class="empty">暂无记录</view>
|
<view v-if="detail.records.length === 0" class="empty">暂无记录</view>
|
||||||
</uni-card>
|
</uni-card>
|
||||||
|
|
||||||
<view v-if="detail.permissions.canEdit || detail.permissions.canSubmit" class="actions">
|
<view v-if="hasActions" class="actions">
|
||||||
<button
|
<button
|
||||||
v-if="detail.permissions.canEdit"
|
v-if="detail.myTask && detail.permissions.canApprove"
|
||||||
class="action-button ghost"
|
class="action-button primary"
|
||||||
@click="editDraft"
|
@click="openApprove"
|
||||||
>
|
>
|
||||||
编辑
|
通过
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="detail.myTask && detail.permissions.canReject"
|
||||||
|
class="action-button danger"
|
||||||
|
@click="openReject"
|
||||||
|
>
|
||||||
|
驳回
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="detail.permissions.canWithdraw"
|
||||||
|
class="action-button ghost"
|
||||||
|
:loading="submitting"
|
||||||
|
@click="withdraw"
|
||||||
|
>
|
||||||
|
撤回
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="showEditButton"
|
||||||
|
class="action-button ghost"
|
||||||
|
@click="editAndResubmit"
|
||||||
|
>
|
||||||
|
{{ editLabel }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="detail.permissions.canSubmit"
|
v-if="detail.permissions.canSubmit"
|
||||||
@@ -123,9 +145,27 @@
|
|||||||
:loading="submitting"
|
:loading="submitting"
|
||||||
@click="submitDraft"
|
@click="submitDraft"
|
||||||
>
|
>
|
||||||
提交
|
{{ detail.status === 'DRAFT' ? '提交' : '重新提交' }}
|
||||||
</button>
|
</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view v-if="actionDialog" class="dialog-mask">
|
||||||
|
<view class="dialog">
|
||||||
|
<text class="dialog-title">{{ actionDialog === 'approve' ? '审批意见' : '驳回意见' }}</text>
|
||||||
|
<textarea
|
||||||
|
v-model="opinion"
|
||||||
|
class="dialog-input"
|
||||||
|
:maxlength="500"
|
||||||
|
:placeholder="actionDialog === 'approve' ? '请输入意见(可选)' : '请输入驳回意见(必填)'"
|
||||||
|
/>
|
||||||
|
<view class="dialog-actions">
|
||||||
|
<button class="dialog-button ghost" @click="closeDialog">取消</button>
|
||||||
|
<button class="dialog-button primary" :loading="submitting" @click="confirmAction">
|
||||||
|
确定
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view v-else class="loading">
|
<view v-else class="loading">
|
||||||
<text>{{ loading ? '加载中...' : '单据不存在' }}</text>
|
<text>{{ loading ? '加载中...' : '单据不存在' }}</text>
|
||||||
@@ -134,9 +174,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { onLoad } from '@dcloudio/uni-app';
|
import { onLoad } from '@dcloudio/uni-app';
|
||||||
import { getInstance, submitInstance } from '@/api/approval/instance';
|
import { getInstance, submitInstance } from '@/api/approval/instance';
|
||||||
|
import {
|
||||||
|
approveTask,
|
||||||
|
rejectTask,
|
||||||
|
withdrawInstance
|
||||||
|
} from '@/api/approval/task';
|
||||||
import type { ApprovalInstance } from '@/api/approval/model';
|
import type { ApprovalInstance } from '@/api/approval/model';
|
||||||
import { showError } from '@/utils/app';
|
import { showError } from '@/utils/app';
|
||||||
|
|
||||||
@@ -144,6 +189,28 @@ const detail = ref<ApprovalInstance | null>(null);
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const submitting = ref(false);
|
const submitting = ref(false);
|
||||||
const instanceId = ref(0);
|
const instanceId = ref(0);
|
||||||
|
const actionDialog = ref<'' | 'approve' | 'reject'>('');
|
||||||
|
const opinion = ref('');
|
||||||
|
|
||||||
|
const hasActions = computed(() => {
|
||||||
|
const permissions = detail.value?.permissions;
|
||||||
|
if (!permissions) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
permissions.canApprove ||
|
||||||
|
permissions.canReject ||
|
||||||
|
permissions.canWithdraw ||
|
||||||
|
permissions.canSubmit ||
|
||||||
|
permissions.canEdit
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const showEditButton = computed(() => !!detail.value?.permissions.canEdit);
|
||||||
|
const editLabel = computed(() =>
|
||||||
|
detail.value?.status === 'REJECTED' || detail.value?.status === 'WITHDRAWN'
|
||||||
|
? '修改并重新提交'
|
||||||
|
: '编辑'
|
||||||
|
);
|
||||||
|
|
||||||
onLoad(options => {
|
onLoad(options => {
|
||||||
instanceId.value = Number(options?.id) || 0;
|
instanceId.value = Number(options?.id) || 0;
|
||||||
@@ -164,13 +231,85 @@ async function load() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function editDraft() {
|
function editAndResubmit() {
|
||||||
|
if (detail.value?.docType !== 'completion') {
|
||||||
|
showError('该单据类型暂不支持在线修改', null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url:
|
url:
|
||||||
'/packageApproval/pages/form-completion?mode=edit&id=' + instanceId.value
|
'/packageApproval/pages/form-completion?mode=edit&id=' + instanceId.value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openApprove() {
|
||||||
|
opinion.value = '';
|
||||||
|
actionDialog.value = 'approve';
|
||||||
|
}
|
||||||
|
|
||||||
|
function openReject() {
|
||||||
|
opinion.value = '';
|
||||||
|
actionDialog.value = 'reject';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDialog() {
|
||||||
|
if (submitting.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
actionDialog.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmAction() {
|
||||||
|
const taskId = detail.value?.myTask?.id;
|
||||||
|
if (!taskId) {
|
||||||
|
showError('任务已处理,请刷新后重试', null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isApprove = actionDialog.value === 'approve';
|
||||||
|
if (!isApprove && !opinion.value.trim()) {
|
||||||
|
uni.showToast({ title: '请填写驳回意见', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
submitting.value = true;
|
||||||
|
try {
|
||||||
|
const response = isApprove
|
||||||
|
? await approveTask(taskId, opinion.value.trim() || undefined)
|
||||||
|
: await rejectTask(taskId, opinion.value.trim());
|
||||||
|
actionDialog.value = '';
|
||||||
|
uni.showToast({
|
||||||
|
title: response.message || (isApprove ? '已通过' : '已驳回'),
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
await load();
|
||||||
|
} catch (error: any) {
|
||||||
|
showError(error?.message || '操作失败', null);
|
||||||
|
} finally {
|
||||||
|
submitting.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function withdraw() {
|
||||||
|
uni.showModal({
|
||||||
|
title: '撤回确认',
|
||||||
|
content: '撤回后单据回到报送人,可修改后重新提交。确认撤回?',
|
||||||
|
success: async result => {
|
||||||
|
if (!result.confirm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
submitting.value = true;
|
||||||
|
try {
|
||||||
|
const response = await withdrawInstance(instanceId.value);
|
||||||
|
uni.showToast({ title: response.message || '撤回成功', icon: 'none' });
|
||||||
|
await load();
|
||||||
|
} catch (error: any) {
|
||||||
|
showError(error?.message || '撤回失败', null);
|
||||||
|
} finally {
|
||||||
|
submitting.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function submitDraft() {
|
function submitDraft() {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '提交确认',
|
title: '提交确认',
|
||||||
@@ -411,12 +550,14 @@ function formatSize(value?: number) {
|
|||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
gap: 24rpx;
|
gap: 24rpx;
|
||||||
padding: 24rpx 32rpx 48rpx;
|
padding: 24rpx 32rpx 48rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 200rpx;
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
border-radius: 12rpx;
|
border-radius: 12rpx;
|
||||||
}
|
}
|
||||||
@@ -432,6 +573,74 @@ function formatSize(value?: number) {
|
|||||||
border: 1rpx solid #dcdfe6;
|
border: 1rpx solid #dcdfe6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-button.danger {
|
||||||
|
background: #ffffff;
|
||||||
|
color: #cf1322;
|
||||||
|
border: 1rpx solid #cf1322;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-mask {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.45);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
width: 600rpx;
|
||||||
|
padding: 32rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 180rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
padding: 16rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 26rpx;
|
||||||
|
background: #f5f6f8;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
margin-top: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-button {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 28rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-button.primary {
|
||||||
|
background: #d81e06;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-button.ghost {
|
||||||
|
background: #ffffff;
|
||||||
|
color: #303133;
|
||||||
|
border: 1rpx solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
padding: 160rpx 0;
|
padding: 160rpx 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="activeTab === 'mine'" class="toolbar">
|
<view class="toolbar">
|
||||||
<picker :range="statusLabels" :value="statusIndex" @change="onStatusChange">
|
<picker :range="statusLabels" :value="statusIndex" @change="onStatusChange">
|
||||||
<view class="filter">{{ statusLabels[statusIndex] }}</view>
|
<view class="filter">{{ statusLabels[statusIndex] }}</view>
|
||||||
</picker>
|
</picker>
|
||||||
@@ -20,18 +20,13 @@
|
|||||||
v-model="keywords"
|
v-model="keywords"
|
||||||
class="search"
|
class="search"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="搜索单号或名称"
|
placeholder="搜索单号、名称或标题"
|
||||||
confirm-type="search"
|
confirm-type="search"
|
||||||
@confirm="reload"
|
@confirm="reload"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="activeTab !== 'mine'" class="placeholder">
|
<view class="list">
|
||||||
<text class="placeholder-title">{{ activeLabel }}功能建设中</text>
|
|
||||||
<text class="placeholder-desc">当前版本先开放「我发起的」</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view v-else class="list">
|
|
||||||
<uni-card
|
<uni-card
|
||||||
v-for="item in list"
|
v-for="item in list"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@@ -61,7 +56,7 @@
|
|||||||
</uni-card>
|
</uni-card>
|
||||||
|
|
||||||
<view v-if="!loading && list.length === 0" class="empty">
|
<view v-if="!loading && list.length === 0" class="empty">
|
||||||
<text>暂无单据</text>
|
<text>{{ emptyText }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="loading" class="loading">
|
<view v-if="loading" class="loading">
|
||||||
<text>加载中...</text>
|
<text>加载中...</text>
|
||||||
@@ -79,9 +74,14 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { onLoad, onPullDownRefresh, onReachBottom, onShow } from '@dcloudio/uni-app';
|
import {
|
||||||
import { pageMine } from '@/api/approval/instance';
|
onLoad,
|
||||||
import type { ApprovalItem } from '@/api/approval/model';
|
onPullDownRefresh,
|
||||||
|
onReachBottom,
|
||||||
|
onShow
|
||||||
|
} from '@dcloudio/uni-app';
|
||||||
|
import { pageDone, pageMine, pageTodo } from '@/api/approval/instance';
|
||||||
|
import type { ApprovalItem, ApprovalTaskListParam } from '@/api/approval/model';
|
||||||
|
|
||||||
type TabKey = 'todo' | 'mine' | 'done';
|
type TabKey = 'todo' | 'mine' | 'done';
|
||||||
|
|
||||||
@@ -102,10 +102,16 @@ const statusOptions = [
|
|||||||
];
|
];
|
||||||
const statusLabels = statusOptions.map(option => option.label);
|
const statusLabels = statusOptions.map(option => option.label);
|
||||||
|
|
||||||
const activeTab = ref<TabKey>('mine');
|
const activeTab = ref<TabKey>('todo');
|
||||||
const activeLabel = computed(
|
const emptyText = computed(() => {
|
||||||
() => tabs.find(tab => tab.key === activeTab.value)?.label || ''
|
if (activeTab.value === 'todo') {
|
||||||
);
|
return '暂无待办';
|
||||||
|
}
|
||||||
|
if (activeTab.value === 'done') {
|
||||||
|
return '暂无已办';
|
||||||
|
}
|
||||||
|
return '暂无单据';
|
||||||
|
});
|
||||||
const statusIndex = ref(0);
|
const statusIndex = ref(0);
|
||||||
const keywords = ref('');
|
const keywords = ref('');
|
||||||
const list = ref<ApprovalItem[]>([]);
|
const list = ref<ApprovalItem[]>([]);
|
||||||
@@ -114,26 +120,23 @@ const limit = 10;
|
|||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const finished = ref(false);
|
const finished = ref(false);
|
||||||
|
let requestSeq = 0;
|
||||||
|
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
load(true);
|
load(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
if (activeTab.value === 'mine') {
|
load(true);
|
||||||
load(true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onPullDownRefresh(async () => {
|
onPullDownRefresh(async () => {
|
||||||
if (activeTab.value === 'mine') {
|
await load(true);
|
||||||
await load(true);
|
|
||||||
}
|
|
||||||
uni.stopPullDownRefresh();
|
uni.stopPullDownRefresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
onReachBottom(() => {
|
onReachBottom(() => {
|
||||||
if (activeTab.value === 'mine' && !loading.value && !finished.value) {
|
if (!loading.value && !finished.value) {
|
||||||
load(false);
|
load(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -143,9 +146,8 @@ function switchTab(key: TabKey) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
activeTab.value = key;
|
activeTab.value = key;
|
||||||
if (key === 'mine' && list.value.length === 0) {
|
list.value = [];
|
||||||
load(true);
|
load(true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStatusChange(event: { detail: { value: string | number } }) {
|
function onStatusChange(event: { detail: { value: string | number } }) {
|
||||||
@@ -154,21 +156,32 @@ function onStatusChange(event: { detail: { value: string | number } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function load(reset: boolean) {
|
async function load(reset: boolean) {
|
||||||
if (loading.value) {
|
if (loading.value && !reset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const seq = ++requestSeq;
|
||||||
|
const tab = activeTab.value;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
page.value = 1;
|
page.value = 1;
|
||||||
finished.value = false;
|
finished.value = false;
|
||||||
}
|
}
|
||||||
const result = await pageMine({
|
const params: ApprovalTaskListParam = {
|
||||||
page: page.value,
|
page: page.value,
|
||||||
limit,
|
limit,
|
||||||
keywords: keywords.value || undefined,
|
keywords: keywords.value || undefined,
|
||||||
status: statusOptions[statusIndex.value].value || undefined
|
status: statusOptions[statusIndex.value].value || undefined
|
||||||
});
|
};
|
||||||
|
const result =
|
||||||
|
tab === 'todo'
|
||||||
|
? await pageTodo(params)
|
||||||
|
: tab === 'done'
|
||||||
|
? await pageDone(params)
|
||||||
|
: await pageMine(params);
|
||||||
|
if (seq !== requestSeq) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
total.value = Number(result.count) || 0;
|
total.value = Number(result.count) || 0;
|
||||||
list.value = reset ? result.list || [] : [...list.value, ...(result.list || [])];
|
list.value = reset ? result.list || [] : [...list.value, ...(result.list || [])];
|
||||||
finished.value = list.value.length >= total.value;
|
finished.value = list.value.length >= total.value;
|
||||||
@@ -176,9 +189,13 @@ async function load(reset: boolean) {
|
|||||||
page.value += 1;
|
page.value += 1;
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
uni.showToast({ title: error?.message || '加载失败', icon: 'none' });
|
if (seq === requestSeq) {
|
||||||
|
uni.showToast({ title: error?.message || '加载失败', icon: 'none' });
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
if (seq === requestSeq) {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,24 +359,6 @@ function formatTime(value?: string) {
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
padding: 160rpx 40rpx;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-title {
|
|
||||||
display: block;
|
|
||||||
font-size: 30rpx;
|
|
||||||
color: #606266;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-desc {
|
|
||||||
display: block;
|
|
||||||
margin-top: 16rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #909399;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty,
|
.empty,
|
||||||
.loading,
|
.loading,
|
||||||
.finished {
|
.finished {
|
||||||
|
|||||||
Reference in New Issue
Block a user