576 lines
14 KiB
Vue
576 lines
14 KiB
Vue
|
|
<template>
|
|||
|
|
<BasicLayout>
|
|||
|
|
<view class="px-15 pb-15">
|
|||
|
|
<!-- 搜索和筛选 -->
|
|||
|
|
<view class="search-section">
|
|||
|
|
<BasicSearch
|
|||
|
|
placeholder="搜索公文标题或编号"
|
|||
|
|
@search="handleSearch"
|
|||
|
|
/>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 筛选标签 -->
|
|||
|
|
<view class="filter-section">
|
|||
|
|
<view class="filter-tabs">
|
|||
|
|
<view
|
|||
|
|
v-for="tab in filterTabs"
|
|||
|
|
:key="tab.key"
|
|||
|
|
class="filter-tab"
|
|||
|
|
:class="{ active: activeTab === tab.key }"
|
|||
|
|
@click="switchTab(tab.key)"
|
|||
|
|
>
|
|||
|
|
{{ tab.label }}
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 公文列表 -->
|
|||
|
|
<view class="gw-list">
|
|||
|
|
<view
|
|||
|
|
v-for="item in filteredGwList"
|
|||
|
|
:key="item.id"
|
|||
|
|
class="gw-item"
|
|||
|
|
@click="goToDetail(item)"
|
|||
|
|
>
|
|||
|
|
<view class="gw-header">
|
|||
|
|
<view class="gw-title">{{ item.title }}</view>
|
|||
|
|
<view class="gw-status" :class="getStatusClass(item.status)">
|
|||
|
|
{{ getStatusText(item.status) }}
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="gw-info">
|
|||
|
|
<view class="info-row">
|
|||
|
|
<text class="label">编号:</text>
|
|||
|
|
<text class="value">{{ item.gwNo }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-row">
|
|||
|
|
<text class="label">类型:</text>
|
|||
|
|
<text class="value">{{ item.gwType }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-row">
|
|||
|
|
<text class="label">紧急程度:</text>
|
|||
|
|
<text class="value urgency-tag" :class="getUrgencyClass(item.urgencyLevel)">
|
|||
|
|
{{ getUrgencyText(item.urgencyLevel) }}
|
|||
|
|
</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="gw-footer">
|
|||
|
|
<view class="approver-info">
|
|||
|
|
<text class="label">审批进度:</text>
|
|||
|
|
<text class="value">{{ getApproverProgress(item) }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="time-info">
|
|||
|
|
<text class="label">创建时间:</text>
|
|||
|
|
<text class="value">{{ formatTime(item.createdTime) }}</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="gw-actions">
|
|||
|
|
<u-button
|
|||
|
|
text="查看详情"
|
|||
|
|
size="mini"
|
|||
|
|
type="primary"
|
|||
|
|
@click.stop="goToDetail(item)"
|
|||
|
|
/>
|
|||
|
|
<u-button
|
|||
|
|
v-if="item.status === GwStatus.DRAFT"
|
|||
|
|
text="编辑"
|
|||
|
|
size="mini"
|
|||
|
|
@click.stop="editGw(item)"
|
|||
|
|
/>
|
|||
|
|
<u-button
|
|||
|
|
v-if="item.status === GwStatus.DRAFT"
|
|||
|
|
text="删除"
|
|||
|
|
size="mini"
|
|||
|
|
type="error"
|
|||
|
|
@click.stop="deleteGw(item)"
|
|||
|
|
/>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 空状态 -->
|
|||
|
|
<view v-if="filteredGwList.length === 0" class="empty-state">
|
|||
|
|
<view class="empty-icon">📄</view>
|
|||
|
|
<view class="empty-text">暂无公文数据</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 加载更多 -->
|
|||
|
|
<view v-if="hasMore && filteredGwList.length > 0" class="load-more">
|
|||
|
|
<u-button
|
|||
|
|
text="加载更多"
|
|||
|
|
@click="loadMore"
|
|||
|
|
:loading="loading"
|
|||
|
|
/>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 底部操作按钮 -->
|
|||
|
|
<template #bottom>
|
|||
|
|
<view class="flex-row items-center pb-10 pt-5">
|
|||
|
|
<u-button
|
|||
|
|
text="新建公文"
|
|||
|
|
class="mx-15"
|
|||
|
|
type="primary"
|
|||
|
|
@click="createNewGw"
|
|||
|
|
/>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
</BasicLayout>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup lang="ts">
|
|||
|
|
import { ref, computed, onMounted } from "vue";
|
|||
|
|
import { navigateTo } from "@/utils/uniapp";
|
|||
|
|
import BasicSearch from "@/components/BasicSearch/Search.vue";
|
|||
|
|
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
|||
|
|
import { getGwListApi, deleteGwApi } from "@/api/routine/gw";
|
|||
|
|
import { GwStatus, UrgencyLevel, ApproverStatus } from "@/types/gw";
|
|||
|
|
import type { GwInfo, GwListItem } from "@/types/gw";
|
|||
|
|
import dayjs from "dayjs";
|
|||
|
|
|
|||
|
|
// 筛选标签
|
|||
|
|
const filterTabs = [
|
|||
|
|
{ key: "all", label: "全部" },
|
|||
|
|
{ key: "draft", label: "草稿" },
|
|||
|
|
{ key: "pending", label: "待审批" },
|
|||
|
|
{ key: "approved", label: "已通过" },
|
|||
|
|
{ key: "rejected", label: "已驳回" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const activeTab = ref("all");
|
|||
|
|
const searchKeyword = ref("");
|
|||
|
|
const gwList = ref<GwListItem[]>([]);
|
|||
|
|
const loading = ref(false);
|
|||
|
|
const hasMore = ref(true);
|
|||
|
|
const page = ref(1);
|
|||
|
|
const pageSize = 20;
|
|||
|
|
|
|||
|
|
// 筛选后的公文列表
|
|||
|
|
const filteredGwList = computed(() => {
|
|||
|
|
let list = gwList.value;
|
|||
|
|
|
|||
|
|
// 按状态筛选
|
|||
|
|
if (activeTab.value !== "all") {
|
|||
|
|
const statusMap: Record<string, GwStatus> = {
|
|||
|
|
draft: GwStatus.DRAFT,
|
|||
|
|
pending: GwStatus.PENDING,
|
|||
|
|
approved: GwStatus.APPROVED,
|
|||
|
|
rejected: GwStatus.REJECTED,
|
|||
|
|
};
|
|||
|
|
const targetStatus = statusMap[activeTab.value];
|
|||
|
|
if (targetStatus) {
|
|||
|
|
list = list.filter(item => item.status === targetStatus);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 按关键词搜索
|
|||
|
|
if (searchKeyword.value) {
|
|||
|
|
const keyword = searchKeyword.value.toLowerCase();
|
|||
|
|
list = list.filter(item =>
|
|||
|
|
item.title.toLowerCase().includes(keyword) ||
|
|||
|
|
item.gwNo.toLowerCase().includes(keyword)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return list;
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 切换筛选标签
|
|||
|
|
const switchTab = (tabKey: string) => {
|
|||
|
|
activeTab.value = tabKey;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 搜索处理
|
|||
|
|
const handleSearch = (keyword: string) => {
|
|||
|
|
searchKeyword.value = keyword;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取公文列表
|
|||
|
|
const getGwList = async (isLoadMore = false) => {
|
|||
|
|
try {
|
|||
|
|
loading.value = true;
|
|||
|
|
|
|||
|
|
if (!isLoadMore) {
|
|||
|
|
page.value = 1;
|
|||
|
|
hasMore.value = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 模拟API调用,实际开发时替换为真实API
|
|||
|
|
const statusMap: Record<string, GwStatus> = {
|
|||
|
|
draft: GwStatus.DRAFT,
|
|||
|
|
pending: GwStatus.PENDING,
|
|||
|
|
approved: GwStatus.APPROVED,
|
|||
|
|
rejected: GwStatus.REJECTED,
|
|||
|
|
};
|
|||
|
|
const targetStatus = activeTab.value === "all" ? undefined : statusMap[activeTab.value];
|
|||
|
|
|
|||
|
|
// 模拟筛选逻辑
|
|||
|
|
let filteredData = mockData;
|
|||
|
|
if (targetStatus) {
|
|||
|
|
filteredData = mockData.filter(item => item.status === targetStatus);
|
|||
|
|
}
|
|||
|
|
if (searchKeyword.value) {
|
|||
|
|
const keyword = searchKeyword.value.toLowerCase();
|
|||
|
|
filteredData = filteredData.filter(item =>
|
|||
|
|
item.title.toLowerCase().includes(keyword) ||
|
|||
|
|
item.gwNo.toLowerCase().includes(keyword)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 模拟分页
|
|||
|
|
const startIndex = (page.value - 1) * pageSize;
|
|||
|
|
const endIndex = startIndex + pageSize;
|
|||
|
|
const result = {
|
|||
|
|
list: filteredData.slice(startIndex, endIndex),
|
|||
|
|
hasMore: endIndex < filteredData.length,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (isLoadMore) {
|
|||
|
|
gwList.value.push(...result.list);
|
|||
|
|
} else {
|
|||
|
|
gwList.value = result.list;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
hasMore.value = result.hasMore;
|
|||
|
|
page.value++;
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error("获取公文列表失败:", error);
|
|||
|
|
uni.showToast({
|
|||
|
|
title: "获取列表失败",
|
|||
|
|
icon: "error",
|
|||
|
|
});
|
|||
|
|
} finally {
|
|||
|
|
loading.value = false;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 加载更多
|
|||
|
|
const loadMore = () => {
|
|||
|
|
if (!loading.value && hasMore.value) {
|
|||
|
|
getGwList(true);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 跳转到详情页面
|
|||
|
|
const goToDetail = (item: GwListItem) => {
|
|||
|
|
navigateTo(`/pages/view/routine/gwlz/gwFlow?id=${item.id}`);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 编辑公文
|
|||
|
|
const editGw = (item: GwListItem) => {
|
|||
|
|
navigateTo(`/pages/view/routine/gwlz?id=${item.id}&mode=edit`);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 删除公文
|
|||
|
|
const deleteGw = (item: GwListItem) => {
|
|||
|
|
uni.showModal({
|
|||
|
|
title: "确认删除",
|
|||
|
|
content: `确定要删除公文"${item.title}"吗?`,
|
|||
|
|
success: async (res) => {
|
|||
|
|
if (res.confirm) {
|
|||
|
|
try {
|
|||
|
|
// 模拟删除API调用
|
|||
|
|
await deleteGwApi(item.id);
|
|||
|
|
|
|||
|
|
// 从本地列表中移除
|
|||
|
|
const index = gwList.value.findIndex(gw => gw.id === item.id);
|
|||
|
|
if (index > -1) {
|
|||
|
|
gwList.value.splice(index, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uni.showToast({
|
|||
|
|
title: "删除成功",
|
|||
|
|
icon: "success",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error("删除公文失败:", error);
|
|||
|
|
uni.showToast({
|
|||
|
|
title: "删除失败",
|
|||
|
|
icon: "error",
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 新建公文
|
|||
|
|
const createNewGw = () => {
|
|||
|
|
navigateTo("/pages/view/routine/gwlz/gwAdd");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取状态样式类
|
|||
|
|
const getStatusClass = (status: GwStatus) => {
|
|||
|
|
const statusMap: Record<GwStatus, string> = {
|
|||
|
|
[GwStatus.DRAFT]: "status-draft",
|
|||
|
|
[GwStatus.PENDING]: "status-pending",
|
|||
|
|
[GwStatus.APPROVED]: "status-approved",
|
|||
|
|
[GwStatus.REJECTED]: "status-rejected",
|
|||
|
|
};
|
|||
|
|
return statusMap[status] || "status-default";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取状态文本
|
|||
|
|
const getStatusText = (status: GwStatus) => {
|
|||
|
|
const statusMap: Record<GwStatus, string> = {
|
|||
|
|
[GwStatus.DRAFT]: "草稿",
|
|||
|
|
[GwStatus.PENDING]: "待审批",
|
|||
|
|
[GwStatus.APPROVED]: "已通过",
|
|||
|
|
[GwStatus.REJECTED]: "已驳回",
|
|||
|
|
};
|
|||
|
|
return statusMap[status] || "未知";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取紧急程度样式类
|
|||
|
|
const getUrgencyClass = (urgency: UrgencyLevel) => {
|
|||
|
|
const urgencyMap: Record<UrgencyLevel, string> = {
|
|||
|
|
[UrgencyLevel.LOW]: "urgency-low",
|
|||
|
|
[UrgencyLevel.NORMAL]: "urgency-normal",
|
|||
|
|
[UrgencyLevel.HIGH]: "urgency-high",
|
|||
|
|
[UrgencyLevel.URGENT]: "urgency-urgent",
|
|||
|
|
};
|
|||
|
|
return urgencyMap[urgency] || "urgency-normal";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取紧急程度文本
|
|||
|
|
const getUrgencyText = (urgency: UrgencyLevel) => {
|
|||
|
|
const urgencyMap: Record<UrgencyLevel, string> = {
|
|||
|
|
[UrgencyLevel.LOW]: "普通",
|
|||
|
|
[UrgencyLevel.NORMAL]: "一般",
|
|||
|
|
[UrgencyLevel.HIGH]: "紧急",
|
|||
|
|
[UrgencyLevel.URGENT]: "特急",
|
|||
|
|
};
|
|||
|
|
return urgencyMap[urgency] || "一般";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取审批进度
|
|||
|
|
const getApproverProgress = (item: GwListItem) => {
|
|||
|
|
if (!item.approvers || item.approvers.length === 0) {
|
|||
|
|
return "无审批人";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const total = item.approvers.length;
|
|||
|
|
const approved = item.approvers.filter((a: any) => a.status === ApproverStatus.APPROVED).length;
|
|||
|
|
const rejected = item.approvers.filter((a: any) => a.status === ApproverStatus.REJECTED).length;
|
|||
|
|
|
|||
|
|
if (rejected > 0) {
|
|||
|
|
return `已驳回 (${rejected}/${total})`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return `${approved}/${total} 已审批`;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 格式化时间
|
|||
|
|
const formatTime = (time: string | Date) => {
|
|||
|
|
return dayjs(time).format("MM-DD HH:mm");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 模拟数据用于开发测试
|
|||
|
|
const mockData: GwListItem[] = [
|
|||
|
|
{
|
|||
|
|
id: "1",
|
|||
|
|
title: "关于2024年教学工作计划的通知",
|
|||
|
|
gwNo: "GW2024001",
|
|||
|
|
gwType: "通知",
|
|||
|
|
urgencyLevel: UrgencyLevel.NORMAL,
|
|||
|
|
status: GwStatus.PENDING,
|
|||
|
|
createdBy: "admin",
|
|||
|
|
createdTime: new Date(),
|
|||
|
|
files: [],
|
|||
|
|
approvers: [
|
|||
|
|
{ id: "1", userId: "user1", userName: "审批人1", deptId: "dept1", deptName: "部门1", order: 1, status: ApproverStatus.APPROVED },
|
|||
|
|
{ id: "2", userId: "user2", userName: "审批人2", deptId: "dept2", deptName: "部门2", order: 2, status: ApproverStatus.PENDING },
|
|||
|
|
],
|
|||
|
|
ccUsers: [],
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "2",
|
|||
|
|
title: "2024年春季学期课程安排",
|
|||
|
|
gwNo: "GW2024002",
|
|||
|
|
gwType: "安排",
|
|||
|
|
urgencyLevel: UrgencyLevel.HIGH,
|
|||
|
|
status: GwStatus.APPROVED,
|
|||
|
|
createdBy: "admin",
|
|||
|
|
createdTime: new Date(Date.now() - 86400000),
|
|||
|
|
files: [],
|
|||
|
|
approvers: [
|
|||
|
|
{ id: "3", userId: "user1", userName: "审批人1", deptId: "dept1", deptName: "部门1", order: 1, status: ApproverStatus.APPROVED },
|
|||
|
|
{ id: "4", userId: "user2", userName: "审批人2", deptId: "dept2", deptName: "部门2", order: 2, status: ApproverStatus.APPROVED },
|
|||
|
|
],
|
|||
|
|
ccUsers: [],
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: "3",
|
|||
|
|
title: "学生宿舍管理规定修订稿",
|
|||
|
|
gwNo: "GW2024003",
|
|||
|
|
gwType: "规定",
|
|||
|
|
urgencyLevel: UrgencyLevel.LOW,
|
|||
|
|
status: GwStatus.DRAFT,
|
|||
|
|
createdBy: "admin",
|
|||
|
|
createdTime: new Date(Date.now() - 172800000),
|
|||
|
|
files: [],
|
|||
|
|
approvers: [],
|
|||
|
|
ccUsers: [],
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
onMounted(() => {
|
|||
|
|
// 使用模拟数据初始化列表
|
|||
|
|
gwList.value = mockData;
|
|||
|
|
});
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.search-section {
|
|||
|
|
margin-bottom: 15px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.filter-section {
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
|
|||
|
|
.filter-tabs {
|
|||
|
|
display: flex;
|
|||
|
|
background: #f5f5f5;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
padding: 4px;
|
|||
|
|
|
|||
|
|
.filter-tab {
|
|||
|
|
flex: 1;
|
|||
|
|
text-align: center;
|
|||
|
|
padding: 8px 12px;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #666;
|
|||
|
|
transition: all 0.3s;
|
|||
|
|
|
|||
|
|
&.active {
|
|||
|
|
background: #007aff;
|
|||
|
|
color: white;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gw-list {
|
|||
|
|
.gw-item {
|
|||
|
|
background: white;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
padding: 15px;
|
|||
|
|
margin-bottom: 15px;
|
|||
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|||
|
|
|
|||
|
|
.gw-header {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: flex-start;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
|
|||
|
|
.gw-title {
|
|||
|
|
flex: 1;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
color: #333;
|
|||
|
|
line-height: 1.4;
|
|||
|
|
margin-right: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gw-status {
|
|||
|
|
padding: 4px 8px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
font-size: 12px;
|
|||
|
|
white-space: nowrap;
|
|||
|
|
|
|||
|
|
&.status-draft { background: #f0f0f0; color: #666; }
|
|||
|
|
&.status-pending { background: #fff7e6; color: #fa8c16; }
|
|||
|
|
&.status-approved { background: #f6ffed; color: #52c41a; }
|
|||
|
|
&.status-rejected { background: #fff2f0; color: #ff4d4f; }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gw-info {
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
|
|||
|
|
.info-row {
|
|||
|
|
display: flex;
|
|||
|
|
margin-bottom: 6px;
|
|||
|
|
|
|||
|
|
.label {
|
|||
|
|
width: 70px;
|
|||
|
|
color: #666;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.value {
|
|||
|
|
flex: 1;
|
|||
|
|
color: #333;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.urgency-tag {
|
|||
|
|
padding: 2px 6px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
font-size: 12px;
|
|||
|
|
|
|||
|
|
&.urgency-low { background: #f6ffed; color: #52c41a; }
|
|||
|
|
&.urgency-normal { background: #f0f0f0; color: #666; }
|
|||
|
|
&.urgency-high { background: #fff7e6; color: #fa8c16; }
|
|||
|
|
&.urgency-urgent { background: #fff2f0; color: #ff4d4f; }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gw-footer {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
margin-bottom: 15px;
|
|||
|
|
font-size: 12px;
|
|||
|
|
|
|||
|
|
.approver-info,
|
|||
|
|
.time-info {
|
|||
|
|
.label {
|
|||
|
|
color: #666;
|
|||
|
|
margin-right: 5px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.value {
|
|||
|
|
color: #333;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gw-actions {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 8px;
|
|||
|
|
justify-content: flex-end;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty-state {
|
|||
|
|
text-align: center;
|
|||
|
|
padding: 60px 20px;
|
|||
|
|
|
|||
|
|
.empty-icon {
|
|||
|
|
font-size: 48px;
|
|||
|
|
margin-bottom: 15px;
|
|||
|
|
opacity: 0.5;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty-text {
|
|||
|
|
color: #999;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.load-more {
|
|||
|
|
text-align: center;
|
|||
|
|
margin-top: 20px;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
|