<template>
|
<view class="contract-management-page">
|
<PageHeader title="合同管理"
|
@back="goBack" />
|
<!-- 搜索栏 -->
|
<view class="search-section">
|
<view class="search-bar">
|
<view class="search-input">
|
<up-input class="search-text"
|
placeholder="请输入员工姓名搜索"
|
v-model="searchValue"
|
@blur="handleSearch"
|
@change="handleSearch"
|
clearable />
|
</view>
|
<view class="filter-button"
|
@click="handleSearch">
|
<u-icon name="search"
|
size="24"
|
color="#999"></u-icon>
|
</view>
|
</view>
|
</view>
|
<!-- 合同信息卡片 -->
|
<view class="contract-card">
|
<!-- 循环展示用户列表 -->
|
<view v-for="(userItem, index) in userList"
|
:key="index"
|
class="user-card">
|
<!-- 基本信息卡片 -->
|
<view class="basic-info-card">
|
<view class="card-header">
|
<text class="card-title">{{ userItem.staffName || '-' }}</text>
|
<text class="card-subtitle"><u-tag :type="userItem.staffState == '1' ? 'primary' : 'error'"
|
:text="userItem.staffState == '1' ? ' 在职 ' : ' 离职 '"></u-tag></text>
|
</view>
|
<view class="card-content">
|
<view class="info-row">
|
<view class="info-item">
|
<text class="info-label">员工编号</text>
|
<text class="info-value">{{ userItem.staffNo || '-' }}</text>
|
</view>
|
<view class="info-item">
|
<text class="info-label">性别</text>
|
<text class="info-value">{{ userItem.sex || '-' }}</text>
|
</view>
|
</view>
|
<view class="info-row">
|
<view class="info-item">
|
<text class="info-label">岗位</text>
|
<text class="info-value">{{ userItem.postJob || '-' }}</text>
|
</view>
|
<view class="info-item">
|
<text class="info-label">第一学历</text>
|
<text class="info-value">{{ userItem.firstStudy || '-' }}</text>
|
</view>
|
</view>
|
<view class="info-row">
|
<view class="info-item">
|
<text class="info-label">专业</text>
|
<text class="info-value">{{ userItem.profession || '-' }}</text>
|
</view>
|
<view class="info-item">
|
<text class="info-label">年龄</text>
|
<text class="info-value">{{ userItem.age || '-' }}</text>
|
</view>
|
</view>
|
<view class="info-row">
|
<view class="info-item">
|
<text class="info-label">联系电话</text>
|
<text class="info-value">{{ userItem.phone || '-' }}</text>
|
</view>
|
</view>
|
<!-- <view class="info-row">
|
<view class="info-item">
|
<text class="info-label">紧急联系人</text>
|
<text class="info-value">{{ userItem.emergencyContact || '-' }}</text>
|
</view>
|
<view class="info-item">
|
<text class="info-label">紧急联系人电话</text>
|
<text class="info-value">{{ userItem.emergencyContactPhone || '-' }}</text>
|
</view>
|
</view> -->
|
<!-- <view class="info-row">
|
<view class="info-item">
|
<text class="info-label">户籍住址</text>
|
<text class="info-value">{{ userItem.nativePlace || '-' }}</text>
|
</view>
|
</view> -->
|
<view class="info-row">
|
<view class="info-item">
|
<text class="info-label">现住址</text>
|
<text class="info-value">{{ userItem.adress || '-' }}</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
<!-- 合同列表卡片 -->
|
<view class="contract-list-card">
|
<view class="card-header">
|
<up-button size="small"
|
:type="userItem.contractExpanded ? 'default' : 'primary'"
|
:loading="userItem.contractLoading"
|
@click="toggleContractExpanded(index)">
|
{{ userItem.contractExpanded ? '隐藏合同列表' : '合同列表' }}<u-icon v-if="userItem.contractExpanded"
|
name="arrow-down"
|
size="12"
|
style="margin-left: 4px;"
|
color="#000"></u-icon>
|
</up-button>
|
</view>
|
<view v-if="(userItem.contractExpanded || userItem.contractLoading) && userItem.contractList.length > 0"
|
class="card-content">
|
<view v-if="userItem.contractLoading"
|
class="list-loading">
|
<u-icon name="loading"
|
size="24"
|
color="#348fe2"></u-icon>
|
<text>加载中...</text>
|
</view>
|
<template v-else>
|
<view v-for="contract in userItem.contractList"
|
:key="contract.id"
|
class="contract-item">
|
<view class="contract-item-header">
|
<text class="contract-name">{{ contract.contractName }}</text>
|
<view class="contract-status"
|
:class="getContractStatusClass(contract.status)">
|
<text>{{ contract.status }}</text>
|
</view>
|
</view>
|
<view class="contract-item-content">
|
<view class="contract-detail">
|
<text class="detail-label">合同年限:</text>
|
<text class="detail-value">{{ contract.contractTerm || '-' }}</text>
|
</view>
|
<view class="contract-detail">
|
<text class="detail-label">合同开始日期:</text>
|
<text class="detail-value">{{ contract.contractStartTime || '-' }}</text>
|
</view>
|
<view class="contract-detail">
|
<text class="detail-label">合同结束日期:</text>
|
<text class="detail-value">{{ contract.contractEndTime || '-' }}</text>
|
</view>
|
</view>
|
</view>
|
</template>
|
</view>
|
</view>
|
</view>
|
<!-- 空状态 -->
|
<view v-if="!loading && userList.length === 0"
|
class="empty-state">
|
<u-icon name="document"
|
size="60"
|
color="#999"></u-icon>
|
<text class="empty-text">暂无合同信息</text>
|
</view>
|
</view>
|
<!-- 加载状态 -->
|
<view v-if="loading"
|
class="loading-state">
|
<u-icon name="loading"
|
size="40"
|
color="#348fe2"></u-icon>
|
<text class="loading-text">加载中...</text>
|
</view>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, onMounted } from "vue";
|
import PageHeader from "@/components/PageHeader.vue";
|
import useUserStore from "@/store/modules/user";
|
import {
|
staffOnJobListPage,
|
findStaffContractListPage,
|
} from "@/api/humanResources/contractManagement";
|
|
// 用户合同信息列表
|
const userList = ref([]);
|
|
// 加载状态
|
const loading = ref(false);
|
|
// 搜索值
|
const searchValue = ref("");
|
|
// 文件列表
|
const fileList = ref([
|
{
|
id: 1,
|
fileName: "劳动合同.pdf",
|
fileSize: "2.5MB",
|
uploadDate: "2026-02-01",
|
},
|
{
|
id: 2,
|
fileName: "保密协议.pdf",
|
fileSize: "1.8MB",
|
uploadDate: "2026-02-01",
|
},
|
{
|
id: 3,
|
fileName: "竞业限制协议.pdf",
|
fileSize: "1.2MB",
|
uploadDate: "2026-02-01",
|
},
|
]);
|
|
// 用户存储
|
const userStore = useUserStore();
|
|
// 返回上一页
|
const goBack = () => {
|
uni.navigateBack();
|
};
|
|
// 获取用户合同信息
|
const getUserContractInfo = (searchName = "") => {
|
loading.value = true;
|
const params = {
|
current: -1,
|
size: -1,
|
staffName: searchName || "",
|
};
|
|
staffOnJobListPage(params)
|
.then(response => {
|
// 为每个用户添加contractList和contractLoading属性
|
userList.value = response.data.records.map(user => ({
|
...user,
|
contractList: [],
|
contractLoading: false,
|
contractExpanded: false,
|
}));
|
})
|
.catch(error => {
|
console.error("获取合同信息失败:", error);
|
})
|
.finally(() => {
|
loading.value = false;
|
});
|
};
|
|
// 加载合同列表
|
const loadContractList = (id, index) => {
|
// 检查用户是否存在
|
console.log(userList.value[index], "userList.value[index]");
|
if (!userList.value[index]) return;
|
|
const userItem = userList.value[index];
|
console.log(userItem.contractList.length, "userItem.contractList.length");
|
// 如果已经加载过,不再重复加载
|
if (userItem.contractList.length > 0) return;
|
|
// 设置加载状态
|
userItem.contractLoading = true;
|
|
// 调用详情接口
|
findStaffContractListPage({ staffOnJobId: id })
|
.then(res => {
|
if (res.data && res.data.records) {
|
userItem.contractList = res.data.records;
|
} else {
|
userItem.contractList = [];
|
}
|
})
|
.finally(() => {
|
// 重置加载状态
|
userItem.contractLoading = false;
|
});
|
};
|
|
// 获取合同状态样式
|
const getContractStatusClass = status => {
|
switch (status) {
|
case "生效中":
|
return "status-active";
|
case "已过期":
|
return "status-expired";
|
case "已终止":
|
return "status-terminated";
|
default:
|
return "status-default";
|
}
|
};
|
|
// 切换合同详情展开/关闭状态
|
const toggleContractExpanded = index => {
|
if (!userList.value[index]) return;
|
|
const userItem = userList.value[index];
|
|
// 如果还没有加载合同列表,先加载数据
|
if (userItem.contractList.length === 0) {
|
loadContractList(userItem.id, index);
|
// 加载完成后自动展开
|
userItem.contractExpanded = true;
|
} else {
|
// 切换展开/关闭状态
|
userItem.contractExpanded = !userItem.contractExpanded;
|
}
|
};
|
|
// 处理搜索
|
const handleSearch = () => {
|
getUserContractInfo(searchValue.value);
|
};
|
|
// 页面加载时获取合同信息
|
onMounted(() => {
|
getUserContractInfo("");
|
});
|
</script>
|
|
<style scoped lang="scss">
|
@import "../../../styles/sales-common.scss";
|
// 全局变量
|
$primary-color: #2c7be5;
|
$primary-light: #4a90e2;
|
$primary-lightest: #e8f0fe;
|
$text-primary: #333333;
|
$text-secondary: #666666;
|
$text-tertiary: #999999;
|
$bg-color: #f8f9fa;
|
$card-bg: #ffffff;
|
$border-color: #e8e8e8;
|
$shadow-sm: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
$shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.12);
|
$border-radius: 16rpx;
|
|
.contract-management-page {
|
min-height: 100vh;
|
background-color: $bg-color;
|
padding-bottom: 40rpx;
|
}
|
|
/* 合同卡片 */
|
.contract-card {
|
margin: 24rpx;
|
display: flex;
|
flex-direction: column;
|
gap: 24rpx;
|
}
|
|
/* 基本信息卡片 */
|
.basic-info-card {
|
background-color: $card-bg;
|
border-radius: $border-radius $border-radius 0 0;
|
box-shadow: $shadow-md;
|
overflow: hidden;
|
transition: all 0.3s ease;
|
}
|
|
/* 合同列表卡片 */
|
.contract-list-card {
|
background-color: $card-bg;
|
border-radius: 0 0 $border-radius $border-radius;
|
box-shadow: $shadow-md;
|
overflow: hidden;
|
border-top: 1rpx solid $border-color;
|
transition: all 0.3s ease;
|
}
|
|
/* 用户卡片 */
|
.user-card {
|
margin-bottom: 0;
|
border-radius: $border-radius;
|
overflow: hidden;
|
box-shadow: $shadow-md;
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
}
|
|
.user-card:hover {
|
transform: translateY(-4rpx);
|
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
|
}
|
|
/* 卡片头部 */
|
.card-header {
|
padding: 24rpx;
|
border-bottom: 1rpx solid $border-color;
|
background-color: $primary-lightest;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
|
.card-title {
|
font-size: 16px;
|
font-weight: 600;
|
color: $primary-color;
|
}
|
|
.card-subtitle {
|
font-size: 13px;
|
color: $text-secondary;
|
padding: 4rpx 12rpx;
|
border-radius: 12rpx;
|
}
|
|
/* 卡片内容 */
|
.card-content {
|
padding: 24rpx;
|
}
|
|
/* 信息行 */
|
.info-row {
|
display: flex;
|
margin-bottom: 20rpx;
|
gap: 20rpx;
|
}
|
|
.info-row:last-child {
|
margin-bottom: 0;
|
}
|
|
/* 信息项 */
|
.info-item {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
padding: 12rpx;
|
background-color: #f9fafb;
|
border-radius: 12rpx;
|
border: 1rpx solid $border-color;
|
}
|
|
/* 信息标签 */
|
.info-label {
|
font-size: 12px;
|
color: $text-secondary;
|
margin-bottom: 6rpx;
|
font-weight: 500;
|
}
|
|
/* 信息值 */
|
.info-value {
|
font-size: 14px;
|
color: $text-primary;
|
font-weight: 500;
|
line-height: 1.4;
|
}
|
|
/* 文件表格 */
|
.file-table {
|
width: 100%;
|
}
|
|
/* 表格头部 */
|
.table-header {
|
display: flex;
|
padding: 12rpx 0;
|
border-bottom: 1rpx solid $border-color;
|
font-weight: 600;
|
font-size: 13px;
|
color: $text-secondary;
|
}
|
|
/* 表格行 */
|
.table-row {
|
display: flex;
|
padding: 16rpx 0;
|
border-bottom: 1rpx solid $border-color;
|
font-size: 13px;
|
color: $text-primary;
|
}
|
|
.table-row:last-child {
|
border-bottom: none;
|
}
|
|
/* 表格列 */
|
.table-col {
|
flex: 1;
|
text-align: center;
|
}
|
|
/* 文件名称列 */
|
.file-name {
|
flex: 2;
|
text-align: left;
|
}
|
|
/* 表格空状态 */
|
.table-empty {
|
padding: 40rpx 0;
|
text-align: center;
|
color: $text-tertiary;
|
font-size: 13px;
|
}
|
|
/* 合同列表 */
|
.contract-list {
|
padding: 16rpx;
|
}
|
|
/* 合同项 */
|
.contract-item {
|
background-color: #f9fafb;
|
border-radius: 12rpx;
|
padding: 16rpx;
|
|
border-left: 4px solid $primary-color;
|
}
|
|
.contract-item:last-child {
|
margin-bottom: 0;
|
}
|
|
/* 合同项头部 */
|
.contract-item-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 12rpx;
|
}
|
|
/* 合同名称 */
|
.contract-name {
|
font-size: 14px;
|
font-weight: 600;
|
color: $text-primary;
|
}
|
|
/* 合同状态 */
|
.contract-status {
|
padding: 4rpx 12rpx;
|
border-radius: 12rpx;
|
font-size: 12px;
|
font-weight: 500;
|
}
|
|
/* 合同状态样式 */
|
.status-active {
|
background-color: #e6f7ee;
|
color: #389e75;
|
}
|
|
.status-expired {
|
background-color: #fff5f5;
|
color: #dc3545;
|
}
|
|
.status-terminated {
|
background-color: #f8f9fa;
|
color: #6c757d;
|
}
|
|
.status-default {
|
background-color: #e9ecef;
|
color: #495057;
|
}
|
|
/* 合同项内容 */
|
.contract-item-content {
|
display: flex;
|
flex-direction: column;
|
gap: 8rpx;
|
}
|
|
/* 合同详情 */
|
.contract-detail {
|
display: flex;
|
font-size: 13px;
|
}
|
|
/* 详情标签 */
|
.detail-label {
|
color: $text-secondary;
|
margin-right: 8rpx;
|
}
|
|
/* 详情值 */
|
.detail-value {
|
color: $text-primary;
|
flex: 1;
|
}
|
|
/* 列表空状态 */
|
.list-empty {
|
padding: 40rpx 0;
|
text-align: center;
|
color: $text-tertiary;
|
font-size: 13px;
|
}
|
|
/* 列表加载状态 */
|
.list-loading {
|
padding: 40rpx 0;
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
gap: 12rpx;
|
color: $text-secondary;
|
font-size: 13px;
|
}
|
|
/* 加载状态 */
|
.loading-state {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 100rpx 0;
|
}
|
|
.loading-text {
|
font-size: 14px;
|
color: $text-tertiary;
|
margin-top: 20rpx;
|
}
|
|
/* 空状态 */
|
.empty-state {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 120rpx 0;
|
text-align: center;
|
}
|
|
.empty-text {
|
font-size: 14px;
|
color: $text-tertiary;
|
margin-top: 24rpx;
|
}
|
</style>
|