refactor: 合并 biz_support_unit/biz_execution_unit/biz_service_org 为 biz_org, 删除 2 张孤儿表, 改 biz_person.work_unit → org_id FK
主要改动: - SQL: biz_support_unit → biz_org, 加 org_type, 加 business_nature; 删 biz_execution_unit, biz_service_org - SQL: biz_project.support_unit_id/name + service_org_id/name → org_id/name/type - SQL: biz_meeting.support_unit_name → org_name - SQL: biz_person.work_unit → org_id (FK) - 后端: 新 BizOrg entity/mapper/service/controller - 后端: BizProject/BizMeeting 字段重命名 - 后端: 删 12 个 BizSupportUnit/BizExecutionUnit/BizServiceOrg Java 文件 - 后端: BizPersonImportVO.workUnit → orgName (导入时查 biz_org 取 org_id) - 后端: BizAuthController.registerExecutor 完整实现 (原 registerSupplier stub) - 前端: 新 admin/Orgs.vue + manager/Orgs.vue (原 SupportUnits) - 前端: RegisterExecutor.vue (原 RegisterSupplier, 单页 2 步) - 前端: sponsor/executor/manager 多个文件 workUnit → orgId/orgName 重命名 - 前端: 统一 supplier → executor, 业务命名 sponsor(赞助方) / executor(执行方=供应商) - 前端: 全工程 execution → executor (company type / role / person unit_type)
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div class="page-card">
|
||||
<div class="breadcrumb">首页 / 消息通知</div>
|
||||
|
||||
<ul class="notice-list">
|
||||
<li v-for="n in rows" :key="n.id" class="notice-item" :class="{ read: n.read }">
|
||||
<div class="dot"></div>
|
||||
<div class="body" @click="openDetail(n)">
|
||||
<div class="title"><span class="cat" :class="catClass(n.category)">{{ n.category }}</span>{{ n.title }}</div>
|
||||
<div class="text">{{ n.text }}</div>
|
||||
</div>
|
||||
<span class="time">{{ n.time }}</span>
|
||||
</li>
|
||||
<li v-if="!rows.length" class="empty">暂无消息</li>
|
||||
</ul>
|
||||
|
||||
<el-dialog v-model="detailOpen" :title="detail.title || '消息详情'" width="520px">
|
||||
<div class="detail-body">
|
||||
<div class="meta">
|
||||
<span class="cat" :class="catClass(detail.category)">{{ detail.category }}</span>
|
||||
<span class="time">{{ detail.time }}</span>
|
||||
</div>
|
||||
<div class="text">{{ detail.text || '-' }}</div>
|
||||
</div>
|
||||
<template #footer><el-button @click="detailOpen=false">关闭</el-button></template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { bizList, listMyMessages } from '@/api/public'
|
||||
|
||||
const rows = ref([])
|
||||
const detail = ref({})
|
||||
const detailOpen = ref(false)
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
const r = await listMyMessages({ limit: 50 }); const list = r.rows
|
||||
rows.value = list.map(a => ({
|
||||
id: a.id,
|
||||
category: a.category,
|
||||
title: a.title,
|
||||
text: a.text,
|
||||
time: a.time,
|
||||
read: a.read
|
||||
}))
|
||||
} catch (e) { rows.value = [] }
|
||||
}
|
||||
|
||||
function mapCategory(t) {
|
||||
if (t === 'system') return '系统通知'
|
||||
if (t === 'audit') return '审核结果'
|
||||
if (t === 'project') return '项目动态'
|
||||
if (t === 'meeting') return '会议提醒'
|
||||
return '通知'
|
||||
}
|
||||
|
||||
function catClass(c) {
|
||||
if (c === '系统通知') return 'sys'
|
||||
if (c === '审核结果') return 'audit'
|
||||
if (c === '项目动态') return 'proj'
|
||||
if (c === '会议提醒') return 'meet'
|
||||
return ''
|
||||
}
|
||||
|
||||
function formatAgo(t) {
|
||||
const diff = (Date.now() - new Date(t).getTime()) / 1000
|
||||
if (diff < 3600) return `${Math.floor(diff / 60)} 分钟前`
|
||||
if (diff < 86400) return `${Math.floor(diff / 3600)} 小时前`
|
||||
if (diff < 604800) return `${Math.floor(diff / 86400)} 天前`
|
||||
return new Date(t).toLocaleDateString('zh-CN')
|
||||
}
|
||||
|
||||
function openDetail(n) {
|
||||
detail.value = n
|
||||
detailOpen.value = true
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-card { background: #fff; padding: 16px 20px; border-radius: 6px; border: 1px solid #f0f0f0; }
|
||||
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
|
||||
.notice-list { list-style: none; }
|
||||
.notice-item { padding: 14px 0; border-bottom: 1px solid #f0f0f0; display: flex; align-items: center; gap: 12px; }
|
||||
.notice-item:last-child { border-bottom: none; }
|
||||
.notice-item .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--brand-primary); flex-shrink: 0; }
|
||||
.notice-item.read .dot { background: transparent; border: 1px solid #d9d9d9; }
|
||||
.notice-item .body { flex: 1; min-width: 0; cursor: pointer; }
|
||||
.notice-item .title { font-size: 13px; color: #1a1a1a; display: flex; align-items: center; gap: 8px; }
|
||||
.notice-item.read .title { color: #8c8c8c; }
|
||||
.notice-item .text { font-size: 12px; color: #595959; margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.notice-item .time { font-size: 12px; color: #bfbfbf; flex-shrink: 0; }
|
||||
.notice-item:hover .title { color: var(--brand-primary); }
|
||||
.cat { display: inline-block; font-size: 11px; padding: 1px 6px; border-radius: 2px; background: #f0f0f0; color: #595959; }
|
||||
.cat.sys { background: #e6f7ff; color: var(--brand-primary); }
|
||||
.cat.audit { background: #f9f0ff; color: #722ed1; }
|
||||
.cat.proj { background: #fff7e6; color: #fa8c16; }
|
||||
.cat.meet { background: #f6ffed; color: #52c41a; }
|
||||
.empty { padding: 24px; text-align: center; color: #bfbfbf; font-size: 13px; }
|
||||
.detail-body .meta { display: flex; gap: 12px; align-items: center; margin-bottom: 12px; }
|
||||
.detail-body .text { font-size: 14px; color: #1a1a1a; line-height: 1.6; white-space: pre-wrap; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user