Industrial-image-management.../src/views/system/post/PostDetailDrawer.vue

529 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-drawer
v-model:visible="visible"
title="岗位详情"
width="720px"
unmount-on-close
class="post-detail-drawer"
@close="() => visible = false"
>
<a-spin :loading="loading" class="detail-container">
<div class="detail-card">
<!-- 岗位标题和状态 -->
<div class="detail-header">
<div class="post-name">{{ primaryInfo?.name || '-' }}</div>
<a-tag class="status-tag" :color="getStatusColor(primaryInfo?.status)">
{{ getStatusText(primaryInfo?.status) }}
</a-tag>
</div>
<!-- 标签页菜单 -->
<a-tabs v-model:active-key="activeTab" class="detail-tabs" type="card">
<!-- 1. 基本信息 -->
<a-tab-pane key="basic" title="基本信息">
<div class="tab-content">
<div class="info-grid">
<div class="info-item">
<div class="info-label">岗位名称</div>
<div class="info-value">{{ primaryInfo?.name || '-' }}</div>
</div>
<div class="info-item">
<div class="info-label">所属部门</div>
<div class="info-value">{{ primaryInfo?.department || '技术部' }}</div>
</div>
<div class="info-item">
<div class="info-label">直接上级岗位</div>
<div class="info-value">{{ primaryInfo?.superior || '技术总监' }}</div>
</div>
<div class="info-item">
<div class="info-label">岗位等级/职级</div>
<div class="info-value">{{ primaryInfo?.level || 'P5' }}</div>
</div>
<div class="info-item">
<div class="info-label">编写日期/版本号</div>
<div class="info-value">{{ primaryInfo?.version || '2024-06-01 / V1.0' }}</div>
</div>
<div class="info-item">
<div class="info-label">岗位编号</div>
<div class="info-value">{{ primaryInfo?.id || '10001' }}</div>
</div>
<div class="info-item">
<div class="info-label">工作地点</div>
<div class="info-value">{{ primaryInfo?.location || '上海/远程' }}</div>
</div>
</div>
<!-- 岗位目的 -->
<div class="section-title">岗位目的</div>
<div class="content-container">
<div class="content-text">{{ primaryInfo?.summary || '负责公司核心产品开发,支撑业务增长。' }}</div>
</div>
</div>
</a-tab-pane>
<!-- 2. 工作职责 -->
<a-tab-pane key="tasks" title="工作职责">
<div class="tab-content">
<!-- 主要职责与工作任务 -->
<div class="section-title">主要职责与工作任务</div>
<div class="content-container">
<ul>
<li v-for="(task, idx) in (primaryInfo?.tasks || ['负责XXX产品的需求分析、架构设计、核心模块编码和单元测试。','制定并执行季度社交媒体营销计划,提升品牌曝光度和用户互动率。'])" :key="idx">{{ task }}</li>
</ul>
</div>
<!-- 工作权限 -->
<div class="section-title">工作权限</div>
<div class="content-container">
<ul>
<li v-for="(perm, idx) in (primaryInfo?.permissions || ['有权审批部门内5000元以下的采购申请。','有权对项目团队成员的工作任务进行分配和调整。'])" :key="idx">{{ perm }}</li>
</ul>
</div>
<!-- 汇报关系 -->
<div class="section-title">汇报关系</div>
<div class="info-grid">
<div class="info-item">
<div class="info-label">直接上级</div>
<div class="info-value">{{ primaryInfo?.superior || '技术总监' }}</div>
</div>
<div class="info-item">
<div class="info-label">直接下级</div>
<div class="info-value">{{ primaryInfo?.subordinates || '无' }}</div>
</div>
<div class="info-item">
<div class="info-label">协作关系</div>
<div class="info-value">{{ primaryInfo?.collaboration || '与产品部、销售部、客服部紧密合作' }}</div>
</div>
</div>
</div>
</a-tab-pane>
<!-- 3. 任职资格 -->
<a-tab-pane key="qualifications" title="任职资格">
<div class="tab-content">
<div class="info-grid">
<div class="info-item">
<div class="info-label">教育背景</div>
<div class="info-value">{{ primaryInfo?.education || '本科及以上学历,计算机相关专业' }}</div>
</div>
<div class="info-item">
<div class="info-label">工作经验</div>
<div class="info-value">{{ primaryInfo?.experience || '5年以上相关工作经验' }}</div>
</div>
<div class="info-item">
<div class="info-label">专业知识与技能</div>
<div class="info-value">{{ primaryInfo?.skills || '精通Java/Python良好的沟通与团队协作能力' }}</div>
</div>
<div class="info-item">
<div class="info-label">证书/执照</div>
<div class="info-value">{{ primaryInfo?.certificates || 'PMP、注册会计师等' }}</div>
</div>
<div class="info-item">
<div class="info-label">其他要求</div>
<div class="info-value">{{ primaryInfo?.otherRequirements || '英语流利,能适应短期出差' }}</div>
</div>
</div>
</div>
</a-tab-pane>
<!-- 4. 工作条件 -->
<a-tab-pane key="conditions" title="工作条件">
<div class="tab-content">
<div class="info-grid">
<div class="info-item">
<div class="info-label">工作环境</div>
<div class="info-value">{{ primaryInfo?.workEnv || '办公室/远程' }}</div>
</div>
<div class="info-item">
<div class="info-label">工作时间</div>
<div class="info-value">{{ primaryInfo?.workTime || '标准工时,偶有加班' }}</div>
</div>
<div class="info-item">
<div class="info-label">出差要求</div>
<div class="info-value">{{ primaryInfo?.travel || '偶尔出差' }}</div>
</div>
<div class="info-item">
<div class="info-label">体力要求</div>
<div class="info-value">{{ primaryInfo?.physical || '无特殊要求' }}</div>
</div>
<div class="info-item">
<div class="info-label">特殊设备/工具</div>
<div class="info-value">{{ primaryInfo?.tools || '电脑、办公软件' }}</div>
</div>
<div class="info-item">
<div class="info-label">健康与安全</div>
<div class="info-value">{{ primaryInfo?.health || '注意用眼卫生' }}</div>
</div>
</div>
</div>
</a-tab-pane>
<!-- 5. 绩效与薪酬 -->
<a-tab-pane key="performance" title="绩效与薪酬">
<div class="tab-content">
<!-- 绩效衡量标准 -->
<div class="section-title">绩效衡量标准</div>
<div class="content-container">
<div class="content-text">{{ primaryInfo?.performance || '根据项目按时交付率、代码质量、产品性能指标提升情况进行评估。' }}</div>
</div>
<!-- 薪酬范围 -->
<div class="section-title">薪酬范围</div>
<div class="content-container">
<div class="content-text salary-value">{{ primaryInfo?.salaryRange || '20-30万/年' }}</div>
</div>
</div>
</a-tab-pane>
<!-- 6. 企业文化与发展 -->
<a-tab-pane key="culture" title="企业文化与发展">
<div class="tab-content">
<!-- 公司文化与价值观要求 -->
<div class="section-title">公司文化与价值观要求</div>
<div class="content-container">
<div class="content-text">{{ primaryInfo?.culture || '客户第一、创新、诚信、合作' }}</div>
</div>
<!-- 职业发展路径 -->
<div class="section-title">职业发展路径</div>
<div class="content-container">
<div class="content-text">{{ primaryInfo?.careerPath || '可晋升为高级工程师、技术经理,或横向发展至产品/项目管理岗位。' }}</div>
</div>
</div>
</a-tab-pane>
<!-- 7. 时间信息 -->
<a-tab-pane key="time" title="时间信息">
<div class="tab-content">
<div class="info-grid">
<div class="info-item">
<div class="info-label">创建时间</div>
<div class="info-value">{{ primaryInfo?.createTime || '-' }}</div>
</div>
<div class="info-item">
<div class="info-label">更新时间</div>
<div class="info-value">{{ primaryInfo?.updateTime || '-' }}</div>
</div>
</div>
</div>
</a-tab-pane>
</a-tabs>
</div>
</a-spin>
<template #footer>
<div class="footer-actions">
<a-button type="primary" @click="handleClose">关闭详情</a-button>
</div>
</template>
</a-drawer>
</template>
<script setup lang="ts">
import { nextTick, ref } from 'vue'
import { getPostDetail } from '@/apis/system/post'
import { useLoading } from '@/hooks'
defineOptions({ name: 'PostDetailDrawer' })
const visible = ref(false)
const { loading, setLoading } = useLoading()
const primaryInfo = ref<any>(null)
const activeTab = ref('basic')
// 获取详情
const getDetail = async (id: string) => {
try {
setLoading(true)
primaryInfo.value = null
const response = await getPostDetail(id)
const data = response?.data || response
if (data && typeof data === 'object') {
primaryInfo.value = {
id: data.postId ?? data.id ?? '10001',
name: data.postName ?? data.name ?? '-',
status: data.status,
department: data.department ?? '技术部',
superior: data.superior ?? '技术总监',
level: data.level ?? 'P5',
version: data.version ?? '2024-06-01 / V1.0',
location: data.location ?? '上海/远程',
summary: data.summary ?? '负责公司核心产品开发,支撑业务增长。',
tasks: data.tasks ?? [
'负责XXX产品的需求分析、架构设计、核心模块编码和单元测试。',
'制定并执行季度社交媒体营销计划,提升品牌曝光度和用户互动率。'
],
permissions: data.permissions ?? [
'有权审批部门内5000元以下的采购申请。',
'有权对项目团队成员的工作任务进行分配和调整。'
],
subordinates: data.subordinates ?? '无',
collaboration: data.collaboration ?? '与产品部、销售部、客服部紧密合作',
education: data.education ?? '本科及以上学历,计算机相关专业',
experience: data.experience ?? '5年以上相关工作经验',
skills: data.skills ?? '精通Java/Python良好的沟通与团队协作能力',
certificates: data.certificates ?? 'PMP、注册会计师等',
otherRequirements: data.otherRequirements ?? '英语流利,能适应短期出差',
workEnv: data.workEnv ?? '办公室/远程',
workTime: data.workTime ?? '标准工时,偶有加班',
travel: data.travel ?? '偶尔出差',
physical: data.physical ?? '无特殊要求',
tools: data.tools ?? '电脑、办公软件',
health: data.health ?? '注意用眼卫生',
performance: data.performance ?? '根据项目按时交付率、代码质量、产品性能指标提升情况进行评估。',
careerPath: data.careerPath ?? '可晋升为高级工程师、技术经理,或横向发展至产品/项目管理岗位。',
salaryRange: data.salaryRange ?? '20-30万/年',
culture: data.culture ?? '客户第一、创新、诚信、合作',
createTime: data.createTime,
updateTime: data.updateTime,
}
}
} catch (error: any) {
console.error('获取岗位详情失败:', error)
} finally {
setLoading(false)
}
}
// 获取状态文本
const getStatusText = (status: number | string) => {
if (status === 1 || status === '1') return '正常'
if (status === 0 || status === '0') return '停用'
return '未知状态'
}
// 获取状态标签颜色
const getStatusColor = (status: number | string) => {
if (status === 1 || status === '1') return 'rgb(82, 196, 26)'
if (status === 0 || status === '0') return 'rgb(245, 34, 45)'
return 'rgb(150, 150, 150)'
}
const handleClose = () => {
visible.value = false
}
const onDetail = async (id: string) => {
if (!id) return
visible.value = true
activeTab.value = 'basic' // 重置到第一个标签页
await nextTick()
await getDetail(id)
}
defineExpose({
onDetail,
})
</script>
<style scoped>
.post-detail-drawer {
--primary-color: #3498db;
--light-bg: #f9fafc;
--border-color: #eaeaea;
--label-color: #666;
--value-color: #333;
--group-title-color: #555;
--group-bg: #f5f7fa;
}
.detail-container {
padding: 16px 24px;
}
.detail-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
padding: 20px;
transition: all 0.3s ease;
}
.detail-header {
display: flex;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid var(--border-color);
}
.post-name {
font-size: 20px;
font-weight: 600;
color: var(--value-color);
margin-right: 15px;
letter-spacing: 0.5px;
}
.status-tag {
padding: 4px 12px;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
border: none;
color: white !important;
}
.detail-tabs {
margin-top: 10px;
}
.tab-content {
padding: 20px 0;
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
}
/* 自定义滚动条样式 */
.tab-content::-webkit-scrollbar {
width: 6px;
}
.tab-content::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.tab-content::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
.tab-content::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 18px;
}
.info-item {
display: flex;
flex-direction: column;
background: white;
padding: 12px 15px;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
border: 1px solid var(--border-color);
transition: transform 0.2s, box-shadow 0.2s;
}
.info-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
}
.info-label {
font-size: 14px;
color: var(--label-color);
margin-bottom: 6px;
font-weight: 500;
display: flex;
align-items: center;
}
.info-label::after {
content: ':';
margin-right: 4px;
}
.info-value {
font-size: 16px;
color: var(--value-color);
font-weight: 500;
word-break: break-word;
}
.salary-value {
color: #e74c3c;
font-weight: 600;
}
.content-container {
padding: 16px;
background: white;
border-radius: 6px;
border: 1px solid var(--border-color);
}
.content-text {
color: var(--value-color);
line-height: 1.7;
font-size: 15px;
white-space: pre-wrap;
word-break: break-word;
}
.section-title {
font-size: 18px;
font-weight: 600;
color: var(--group-title-color);
margin-top: 20px;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border-color);
}
.section-title:first-child {
margin-top: 0;
}
.footer-actions {
display: flex;
justify-content: flex-end;
padding: 16px 24px;
}
/* 标签页样式优化 */
:deep(.arco-tabs-nav) {
background-color: var(--light-bg);
border-radius: 8px;
padding: 4px;
margin-bottom: 16px;
}
:deep(.arco-tabs-nav-tab) {
background-color: transparent;
border: none;
}
:deep(.arco-tabs-tab) {
border-radius: 6px;
margin: 0 2px;
padding: 8px 16px;
font-weight: 400;
font-size: 14px;
transition: all 0.3s ease;
border: 2px solid transparent;
color: #666;
}
:deep(.arco-tabs-tab:hover) {
background-color: rgba(52, 152, 219, 0.1);
color: var(--primary-color);
font-weight: 500;
}
:deep(.arco-tabs-tab-active) {
background-color: var(--primary-color);
color: white !important;
border-color: var(--primary-color);
box-shadow: 0 2px 8px rgba(52, 152, 219, 0.3);
font-weight: 700 !important;
font-size: 15px !important;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
:deep(.arco-tabs-content) {
padding: 0;
}
:deep(.arco-tabs-tabpane) {
padding: 0;
}
</style>