| | |
| | | 路由:/pages/oa/ApproveManage/approve-list/index |
| | | --> |
| | | <template> |
| | | <OaListPage v-if="config" |
| | | :page-key="pageKey" |
| | | :page-config="config" /> |
| | | <view class="approve-list-page sales-account"> |
| | | <PageHeader title="审批列表" |
| | | @back="goBack" /> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input v-model="queryParams.keyword" |
| | | class="search-text" |
| | | placeholder="审批标题 / 审批编号" |
| | | clearable |
| | | @confirm="handleSearch" /> |
| | | </view> |
| | | <view class="filter-button" |
| | | @click="handleSearch"> |
| | | <up-icon name="search" |
| | | size="24" |
| | | color="#999" /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <scroll-view class="list-scroll" |
| | | scroll-y |
| | | :show-scrollbar="false" |
| | | @scrolltolower="loadMore"> |
| | | <view v-if="list.length" |
| | | class="ledger-list"> |
| | | <view v-for="item in list" |
| | | :key="item.id" |
| | | class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" |
| | | size="16" |
| | | color="#ffffff" /> |
| | | </view> |
| | | <text class="item-id">{{ item.title || item.instanceNo || "-" }}</text> |
| | | </view> |
| | | <u-tag :type="statusTagType(item.status)" |
| | | :text="statusText(item.status)" /> |
| | | </view> |
| | | <up-divider /> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">审批编号</text> |
| | | <text class="detail-value">{{ item.instanceNo || "-" }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">模板名称</text> |
| | | <text class="detail-value">{{ item.templateName || "-" }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">业务名称</text> |
| | | <text class="detail-value">{{ item.businessName || "-" }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">申请人</text> |
| | | <text class="detail-value">{{ item.applicantName || "-" }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">当前级别</text> |
| | | <text class="detail-value">{{ formatLevel(item.currentLevel) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">当前审批人</text> |
| | | <text class="detail-value">{{ currentApproverName(item) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">申请时间</text> |
| | | <text class="detail-value">{{ item.applyTime || "-" }}</text> |
| | | </view> |
| | | <view v-if="item.finishTime" |
| | | class="detail-row"> |
| | | <text class="detail-label">完成时间</text> |
| | | <text class="detail-value">{{ item.finishTime }}</text> |
| | | </view> |
| | | </view> |
| | | <view v-if="canEdit(item) || item.isApprove" |
| | | class="action-buttons"> |
| | | <up-button v-if="canEdit(item)" |
| | | class="action-btn" |
| | | size="small" |
| | | @click.stop="goEdit(item)"> |
| | | 编辑 |
| | | </up-button> |
| | | <up-button v-if="item.isApprove" |
| | | class="action-btn" |
| | | size="small" |
| | | type="primary" |
| | | @click.stop="handleApprove(item)"> |
| | | 审批 |
| | | </up-button> |
| | | </view> |
| | | </view> |
| | | <up-loadmore :status="pageStatus" /> |
| | | </view> |
| | | <view v-else |
| | | class="empty-wrap"> |
| | | <up-empty mode="list" |
| | | text="暂无审批数据" /> |
| | | </view> |
| | | </scroll-view> |
| | | |
| | | <view class="fab-button" |
| | | @click="goAdd"> |
| | | <up-icon name="plus" |
| | | size="28" |
| | | color="#ffffff" /> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | /** OA - 审批管理 - 审批列表 */ |
| | | import OaListPage from "../../_components/OaListPage.vue"; |
| | | import { useOaPage } from "../../_utils/useOaPage.js"; |
| | | import { reactive, ref } from "vue"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { listApprovalInstancePage } from "@/api/oa/approvalInstance.js"; |
| | | import { OA_NAV } from "@/config/oaPaths.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | |
| | | const pageKey = "ApproveManage/approve-list"; |
| | | const { config } = useOaPage(pageKey); |
| | | const EDIT_STORAGE_KEY = "oa_approve_instance_edit_row"; |
| | | const userStore = useUserStore(); |
| | | |
| | | const queryParams = reactive({ |
| | | keyword: "", |
| | | }); |
| | | |
| | | const list = ref([]); |
| | | const pageStatus = ref("loadmore"); |
| | | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | const STATUS_TEXT = { |
| | | PENDING: "进行中", |
| | | APPROVED: "已通过", |
| | | REJECTED: "已驳回", |
| | | }; |
| | | |
| | | const STATUS_TAG = { |
| | | PENDING: "warning", |
| | | APPROVED: "success", |
| | | REJECTED: "error", |
| | | }; |
| | | |
| | | const statusText = status => STATUS_TEXT[status] || status || "-"; |
| | | |
| | | const statusTagType = status => STATUS_TAG[status] || "info"; |
| | | |
| | | const formatLevel = level => { |
| | | if (level == null || level === "") return "-"; |
| | | return `第 ${level} 级`; |
| | | }; |
| | | |
| | | const currentApproverName = item => { |
| | | const tasks = item?.tasks; |
| | | if (!Array.isArray(tasks) || !tasks.length) return "-"; |
| | | const pending = tasks.find(t => t.taskStatus === "PENDING"); |
| | | if (pending?.approverName) return pending.approverName; |
| | | const names = [...new Set(tasks.map(t => t.approverName).filter(Boolean))]; |
| | | return names.length ? names.join("、") : "-"; |
| | | }; |
| | | |
| | | const buildListParams = () => { |
| | | const keyword = queryParams.keyword?.trim(); |
| | | const dto = {}; |
| | | if (keyword) { |
| | | if (/[\u4e00-\u9fa5]/.test(keyword)) { |
| | | dto.title = keyword; |
| | | } else { |
| | | dto.instanceNo = keyword; |
| | | } |
| | | } |
| | | return { |
| | | page: { |
| | | current: page.current, |
| | | size: page.size, |
| | | }, |
| | | approvalInstanceDto: dto, |
| | | }; |
| | | }; |
| | | |
| | | const getList = () => { |
| | | if (pageStatus.value === "loading" || pageStatus.value === "nomore") return; |
| | | |
| | | pageStatus.value = "loading"; |
| | | listApprovalInstancePage(buildListParams()) |
| | | .then(res => { |
| | | const pageData = res?.data || {}; |
| | | const records = pageData.records || []; |
| | | const total = pageData.total ?? 0; |
| | | |
| | | if (page.current === 1) { |
| | | list.value = records; |
| | | } else { |
| | | list.value = [...list.value, ...records]; |
| | | } |
| | | |
| | | page.total = total; |
| | | if (list.value.length >= total || records.length < page.size) { |
| | | pageStatus.value = "nomore"; |
| | | } else { |
| | | pageStatus.value = "loadmore"; |
| | | page.current += 1; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | if (page.current === 1) { |
| | | list.value = []; |
| | | } |
| | | pageStatus.value = "loadmore"; |
| | | uni.showToast({ title: "查询失败", icon: "none" }); |
| | | }); |
| | | }; |
| | | |
| | | const handleSearch = () => { |
| | | page.current = 1; |
| | | pageStatus.value = "loadmore"; |
| | | list.value = []; |
| | | getList(); |
| | | }; |
| | | |
| | | const loadMore = () => { |
| | | if (pageStatus.value === "loadmore") { |
| | | getList(); |
| | | } |
| | | }; |
| | | |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | const goAdd = () => { |
| | | uni.navigateTo({ url: OA_NAV.approveListTemplateSelect }); |
| | | }; |
| | | |
| | | const canEdit = item => |
| | | item?.status === "PENDING" && |
| | | String(item.applicantId) === String(userStore.id); |
| | | |
| | | const goEdit = item => { |
| | | if (!item?.id) return; |
| | | uni.setStorageSync(EDIT_STORAGE_KEY, item); |
| | | uni.navigateTo({ |
| | | url: `${OA_NAV.approveListApply}?id=${item.id}`, |
| | | }); |
| | | }; |
| | | |
| | | const handleApprove = item => { |
| | | if (!item?.id) return; |
| | | uni.showToast({ title: "审批详情页待对接", icon: "none" }); |
| | | }; |
| | | |
| | | onShow(() => { |
| | | handleSearch(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "@/styles/sales-common.scss"; |
| | | |
| | | .approve-list-page { |
| | | display: flex; |
| | | flex-direction: column; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .list-scroll { |
| | | flex: 1; |
| | | height: 0; |
| | | padding-bottom: calc(80px + env(safe-area-inset-bottom)); |
| | | } |
| | | |
| | | .empty-wrap { |
| | | padding: 48px 20px; |
| | | } |
| | | |
| | | .action-buttons { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 10px; |
| | | margin-top: 12px; |
| | | padding-top: 12px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .action-btn { |
| | | min-width: 72px; |
| | | } |
| | | </style> |