- NoticeAccept 左侧列表:改为每页50滚动触底预取并追加(hasNext 驱动,加载中/没有更多提示), 已读状态改本地置位(markRead),不再整页重拉列表(重拉会丢已追加分页与滚动位置) - NoticeList 附件列 70→80:图标外包 Tooltip 后内容宽不足,cell ellipsis 会在图标后画出「...」 - NoticeApproval 办件表格:状态/提交人/时间列 width→minWidth 参与余量分配,避免通知列独占宽屏余量;操作列固定150居中 - 流程图弹窗/抽屉 860→740(NewNotice / NoticeSetting / NoticeDetails) - 回退 main.scss 中操作列裸 .ivu-tooltip 的 display:block(会以更高特异性顶掉横排规则致图标竖排),改由 .ivu-table-cell-tooltip 恢复 flex - .gitignore 忽略 vite 配置 bundle 临时产物 vite.config.*.timestamp-*
This commit is contained in:
@@ -116,15 +116,12 @@ h4.subtitle {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
/* 修复表格幻影省略号(2026-10-10):.ivu-table-cell 基础样式自带 text-overflow:ellipsis,
|
||||
tooltip 列(.ivu-tooltip 行内块包装 + width:100%)与操作列(图标外包 Tooltip)未溢出也常显「...」。
|
||||
恢复组件预期的块级/flex 渲染层级即可;内层 .ivu-table-cell-tooltip-content 的真省略号与
|
||||
悬浮 tooltip 不受影响(已在 dev:mock 实测:短内容无省略号、长标题正常截断+悬浮提示)。 */
|
||||
/* 两条同为 3 类特异性(0,3,0):后者居后胜出 → tooltip 列(.ivu-table-cell-tooltip)最终 flex
|
||||
(组件预期布局),操作列裸 .ivu-tooltip 包装取 block。 */
|
||||
.ivu-table .ivu-table-cell > .ivu-tooltip {
|
||||
display: block;
|
||||
}
|
||||
/* 修复表格幻影省略号(2026-10-10):.ivu-table-cell 自带 overflow:hidden + text-overflow:ellipsis,
|
||||
tooltip 列的包装层(.ivu-tooltip 行内块 + width:100%)未溢出也会被画出「...」;
|
||||
恢复组件预期的 flex 层级即可,内层 .ivu-table-cell-tooltip-content 的真省略号与悬浮 tooltip 不受影响。
|
||||
注意:不要再给操作列的裸 .ivu-tooltip 加 display:block——那会以更高特异性顶掉 App.vue 的横排规则,
|
||||
使 operatingHandle 渲染的图标按钮竖排(2026-10-10 踩过,已回退)。 */
|
||||
/* tooltip 列的包装层同时挂 .ivu-tooltip{display:inline-block},靠声明顺序顶掉了组件预期的 flex,这里恢复 */
|
||||
.ivu-table .ivu-table-cell > .ivu-table-cell-tooltip {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -421,7 +421,7 @@ async function saveEditAndLeave(data: NoticeRequest) {
|
||||
</Modal>
|
||||
|
||||
<!-- 流程图 Drawer(后端 DiagramDef 同源 PNG;竖版长图容器内纵向滚动) -->
|
||||
<Drawer v-model="flowDiagramVisible" title="流程示意图" :width="860" :transfer="false"
|
||||
<Drawer v-model="flowDiagramVisible" title="流程示意图" :width="740" :transfer="false"
|
||||
:styles="{ body: { padding: '0' } }">
|
||||
<div class="flow-diagram-frame">
|
||||
<img ref="flowDiagramEl" v-if="flowDiagramSrc" :src="flowDiagramSrc" alt="流程示意图" @load="fitDiagram(flowDiagramEl)" @error="onFlowDiagramError" />
|
||||
|
||||
@@ -8,41 +8,76 @@ import FilePreviewModal from "@/components/FilePreviewModal.vue";
|
||||
import SvgIcon from "@/components/SvgIcon.vue";
|
||||
import Utils from "@/utils";
|
||||
|
||||
/* ============ 左侧列表 ============ */
|
||||
/* ============ 左侧列表(每页 50,滚动到底部加载下一页并追加) ============ */
|
||||
const keyword = ref("");
|
||||
const pageNum = ref(1);
|
||||
const pageSize = ref(50);
|
||||
const PAGE_SIZE = 50;
|
||||
const pageIndex = ref(1);
|
||||
const list = ref<NoticeVo[]>([]);
|
||||
const unreadCount = ref(0);
|
||||
const hasNext = ref(false);
|
||||
const loadingMore = ref(false);
|
||||
const selected = ref(0);
|
||||
|
||||
const { data: page, loading, send: reload } = useRequest(
|
||||
(params: NoticeQuery) => noticeApi.list(params),
|
||||
{
|
||||
immediate: false,
|
||||
initialData: { content: [], total: 0, pageIndex: 1, pageSize: 50, totalPages: 0, hasNext: false, unreadCount: 0 },
|
||||
}
|
||||
);
|
||||
const { send: reload } = useRequest((params: NoticeQuery) => noticeApi.list(params), { immediate: false });
|
||||
|
||||
async function run() {
|
||||
async function fetchList(append: boolean) {
|
||||
const data: NoticePageResult<NoticeVo> = await reload({
|
||||
keyword: keyword.value || "",
|
||||
pageIndex: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
pageIndex: append ? pageIndex.value + 1 : 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
orderByTime: "1",
|
||||
});
|
||||
const content = data?.content || [];
|
||||
if (append) {
|
||||
list.value = list.value.concat(content);
|
||||
pageIndex.value += 1;
|
||||
} else {
|
||||
list.value = content;
|
||||
pageIndex.value = 1;
|
||||
}
|
||||
unreadCount.value = data?.unreadCount || 0;
|
||||
hasNext.value = !!data?.hasNext;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
await fetchList(false);
|
||||
// 默认选中第一条(同旧版进入页面即展示最新通知)
|
||||
const list = data?.content || [];
|
||||
if (!detail.value && list.length) {
|
||||
const first = list.value[0];
|
||||
if (!detail.value && first) {
|
||||
selected.value = 0;
|
||||
await loadDetail(list[0].id, true);
|
||||
await loadDetail(first.id, true);
|
||||
markRead(first);
|
||||
}
|
||||
}
|
||||
function onSearch() {
|
||||
pageNum.value = 1;
|
||||
run();
|
||||
|
||||
/* 触底预取:距底部 60px 即发下一页请求,避免滑到尽头才出现内容 */
|
||||
function onListScroll(e: Event) {
|
||||
const el = e.target as HTMLElement;
|
||||
if (!hasNext.value || loadingMore.value) return;
|
||||
if (el.scrollTop + el.clientHeight < el.scrollHeight - 60) return;
|
||||
loadMore();
|
||||
}
|
||||
async function loadMore() {
|
||||
loadingMore.value = true;
|
||||
try {
|
||||
await fetchList(true);
|
||||
} catch (e: any) {
|
||||
Message.error(e?.message || "加载更多失败");
|
||||
} finally {
|
||||
loadingMore.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 已读状态本地置位:标读接口已改库,无需重拉列表(重拉会丢掉已追加的分页与滚动位置) */
|
||||
function markRead(item: NoticeVo) {
|
||||
if (item.read) return;
|
||||
item.read = true;
|
||||
unreadCount.value = Math.max(0, unreadCount.value - 1);
|
||||
}
|
||||
|
||||
function onClear() {
|
||||
keyword.value = "";
|
||||
onSearch();
|
||||
run();
|
||||
}
|
||||
|
||||
/* 一键已读(旧版 icon-saoba 清除按钮) */
|
||||
@@ -50,7 +85,8 @@ async function allRead() {
|
||||
try {
|
||||
await noticeApi.initializeRed().send();
|
||||
Message.success("操作成功!");
|
||||
run();
|
||||
list.value.forEach(markRead);
|
||||
unreadCount.value = 0;
|
||||
if (detail.value) loadDetail(detail.value.serid, false);
|
||||
} catch (e: any) {
|
||||
Message.error(e.message || "操作失败");
|
||||
@@ -68,16 +104,13 @@ onMounted(async () => {
|
||||
async function checkNotice(item: NoticeVo, index: number) {
|
||||
selected.value = index;
|
||||
await loadDetail(item.id, true);
|
||||
markRead(item);
|
||||
}
|
||||
|
||||
async function loadDetail(serid: number, markRead: boolean) {
|
||||
async function loadDetail(serid: number, markAsRead: boolean) {
|
||||
detailLoading.value = true;
|
||||
try {
|
||||
detail.value = await noticeApi.modify(serid, markRead ? 1 : 0).send();
|
||||
if (markRead) {
|
||||
// 标读后刷新左侧未读状态
|
||||
run();
|
||||
}
|
||||
detail.value = await noticeApi.modify(serid, markAsRead ? 1 : 0).send();
|
||||
} catch (e: any) {
|
||||
Message.error(e.message || "加载通知失败");
|
||||
} finally {
|
||||
@@ -171,7 +204,7 @@ function shortDate(date: string) {
|
||||
<!-- 左侧通知列表 -->
|
||||
<div class="title-list">
|
||||
<div class="total">
|
||||
<span>未读<span class="num">{{ page.unreadCount || 0 }}</span>条</span>
|
||||
<span>未读<span class="num">{{ unreadCount }}</span>条</span>
|
||||
<Tooltip content="一键已读" placement="top" transfer>
|
||||
<SvgIcon class="clear-icon" name="read-all" :size="18" color="var(--text-3)" hover-color="var(--brand)" @click="allRead" />
|
||||
</Tooltip>
|
||||
@@ -182,13 +215,13 @@ function shortDate(date: string) {
|
||||
clearable
|
||||
search
|
||||
placeholder="搜索发布人,标题,部门......"
|
||||
@on-search="onSearch"
|
||||
@on-search="run"
|
||||
@on-clear="onClear"
|
||||
></Input>
|
||||
</div>
|
||||
<div class="notice-items">
|
||||
<div class="notice-items" @scroll="onListScroll">
|
||||
<div
|
||||
v-for="(item, index) in page.content"
|
||||
v-for="(item, index) in list"
|
||||
:key="item.id"
|
||||
:class="{ list_item: true, readed: item.read, active: index == selected }"
|
||||
@click="checkNotice(item, index)"
|
||||
@@ -199,7 +232,9 @@ function shortDate(date: string) {
|
||||
<span>{{ shortDate(item.createTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!page.content.length" class="empty">暂无通知</div>
|
||||
<div v-if="loadingMore" class="load-more">加载中...</div>
|
||||
<div v-else-if="list.length && !hasNext" class="load-more">没有更多了</div>
|
||||
<div v-if="!list.length" class="empty">暂无通知</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -381,6 +416,12 @@ function shortDate(date: string) {
|
||||
color: var(--text-3);
|
||||
padding: 40px 0;
|
||||
}
|
||||
.load-more {
|
||||
padding: 10px 0 4px;
|
||||
text-align: center;
|
||||
font-size: 11.5px;
|
||||
color: var(--text-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,13 +123,16 @@ const todoCols = [
|
||||
{ title: "操作", slot: "action", width: 190, align: "center" },
|
||||
];
|
||||
|
||||
/* 列宽:iView 把表格的剩余宽度全部分给「未设 width」的列(table.vue handleResize),
|
||||
原先只有通知列可变 → 宽屏下通知列独占全部余量。改为各列都给 minWidth 参与分配,
|
||||
通知列不再被拉宽;操作列固定 150 且居中。 */
|
||||
const instCols = [
|
||||
{ title: "通知", key: "bizTitle", minWidth: 240, ellipsis: true, tooltip: true },
|
||||
{ title: "状态", slot: "status", width: 100 },
|
||||
{ title: "提交人", key: "submitterName", width: 100 },
|
||||
{ title: "提交时间", key: "submitTime", width: 170, render: fmtTime },
|
||||
{ title: "办结时间", key: "finishTime", width: 170, render: fmtTime },
|
||||
{ title: "操作", slot: "instAction", width: 100 },
|
||||
{ title: "状态", slot: "status", minWidth: 100 },
|
||||
{ title: "提交人", key: "submitterName", minWidth: 100 },
|
||||
{ title: "提交时间", key: "submitTime", minWidth: 170, render: fmtTime },
|
||||
{ title: "办结时间", key: "finishTime", minWidth: 170, render: fmtTime },
|
||||
{ title: "操作", slot: "instAction", width: 150, align: "center" },
|
||||
];
|
||||
|
||||
/* 审批记录 Drawer(嵌入页 iframe):pageUrl 含 10 分钟短时 token,每次打开现取,
|
||||
|
||||
@@ -346,7 +346,7 @@ function openPreview(item: { name?: string; filename?: string; fileid?: number;
|
||||
</div>
|
||||
|
||||
<!-- 流程图弹窗(后端同源出图,免 token 免跨域) -->
|
||||
<Modal v-model="diagramVisible" title="流程示意图" :width="860" footer-hide>
|
||||
<Modal v-model="diagramVisible" title="流程示意图" :width="740" footer-hide>
|
||||
<div class="diagram-wrap">
|
||||
<img v-if="diagramSrc" ref="diagramEl" :src="diagramSrc" alt="流程示意图" @load="fitDiagram(diagramEl)" @error="onDiagramError" />
|
||||
</div>
|
||||
|
||||
@@ -189,7 +189,9 @@ const columns = [
|
||||
},
|
||||
{
|
||||
title: "附件",
|
||||
width: 70,
|
||||
/* 图标外包 Tooltip 后占 32+2*2=36px,cell 左右内边距各 18px:70px 列只剩 34px 内容宽,
|
||||
溢出 2px 会让 cell 的 text-overflow:ellipsis 在图标后画出「...」,故留到 80 */
|
||||
width: 80,
|
||||
align: "center",
|
||||
render: (h: any, p: any) =>
|
||||
(p.row.upFile ?? p.row.UpFile)
|
||||
|
||||
@@ -552,7 +552,7 @@ const groupH = useElementHeight(groupRegionRef);
|
||||
</div>
|
||||
|
||||
<!-- 流程图 Drawer(后端 DiagramDef 同源 PNG;竖版长图容器内纵向滚动) -->
|
||||
<Drawer v-model="flowDiagramVisible" title="流程示意图" :width="860" :transfer="false"
|
||||
<Drawer v-model="flowDiagramVisible" title="流程示意图" :width="740" :transfer="false"
|
||||
:styles="{ body: { padding: '0' } }">
|
||||
<div class="flow-diagram-frame">
|
||||
<img ref="flowDiagramEl" v-if="flowDiagramSrc" :src="flowDiagramSrc" alt="流程示意图" @load="fitDiagram(flowDiagramEl)" @error="onFlowDiagramError" />
|
||||
|
||||
Reference in New Issue
Block a user