生产模块拆分为前缫/后缫;修复菜单卡顿与重复请求;支持 IIS 单站点部署
1. 生产模块按工序拆分为两个一级菜单 - 生产-前缫(落丝记录)、生产-后缫(纤度检验、黑板检验) - 旧的「生产管理」(/prod) 目录及子菜单由种子自动清理,页面组件与权限标识保持不变 - 消息中心跳转路径、首页快捷入口路径同步更新 2. 职工管理独立为一级菜单(原挂在「基础数据」目录下),并清理历史子菜单 3. 修复侧边栏菜单展开卡顿(基础数据等子项较多的目录尤其明显) - 去掉 Element Plus 的 height 过渡动画(会逐帧重排全部子项) - 收起时改用 height:0 + visibility:hidden 而非 display:none,子项提前完成布局 - 菜单区独立滚动并预留滚动条宽度(scrollbar-gutter),消除展开时的横向抖动 - 菜单项增加 contain 布局隔离,淡入动画改为容器级 4. 修复页面首次打开重复请求 - 分页组件挂载时会触发一次 current-change,页码未变化时不再重复加载(18 个页面) - 职工管理去掉 onMounted 与默认选中部门的重复加载 - 工种管理、原料庄口的注册表下拉由按 key 多次请求改为一次全量拉取 5. 后端增加前端静态托管与 SPA 路由回退,支持 IIS 单站点部署(前后端同源) 6. 新增部署脚本 deploy-iis.ps1(首次部署)与 update-iis.ps1(更新发布)
This commit is contained in:
+119
-37
@@ -87,43 +87,45 @@ async function handleLogout() {
|
||||
<el-icon class="logo-icon"><MagicStick /></el-icon>
|
||||
<span v-if="!isCollapse" class="logo-text">智慧缫丝系统</span>
|
||||
</div>
|
||||
<el-menu
|
||||
:default-active="route.path"
|
||||
:collapse="isCollapse"
|
||||
background-color="#0c3b2e"
|
||||
text-color="#b5cdc2"
|
||||
active-text-color="#e8c877"
|
||||
router
|
||||
class="menu"
|
||||
>
|
||||
<el-menu-item index="/dashboard">
|
||||
<el-icon><HomeFilled /></el-icon>
|
||||
<template #title>首页</template>
|
||||
</el-menu-item>
|
||||
|
||||
<template v-for="menu in sidebarMenus" :key="menu.id">
|
||||
<!-- 有子菜单 -->
|
||||
<el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.path">
|
||||
<template #title>
|
||||
<el-icon><component :is="menu.icon || 'Menu'" /></el-icon>
|
||||
<span>{{ menu.name }}</span>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-for="child in menu.children"
|
||||
:key="child.id"
|
||||
:index="child.path"
|
||||
>
|
||||
<el-icon><component :is="child.icon || 'Document'" /></el-icon>
|
||||
<template #title>{{ child.name }}</template>
|
||||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
<!-- 无子菜单 -->
|
||||
<el-menu-item v-else :index="menu.path">
|
||||
<el-icon><component :is="menu.icon || 'Menu'" /></el-icon>
|
||||
<template #title>{{ menu.name }}</template>
|
||||
<div class="menu-wrapper">
|
||||
<el-menu
|
||||
:default-active="route.path"
|
||||
:collapse="isCollapse"
|
||||
background-color="#0c3b2e"
|
||||
text-color="#b5cdc2"
|
||||
active-text-color="#e8c877"
|
||||
router
|
||||
class="menu"
|
||||
>
|
||||
<el-menu-item index="/dashboard">
|
||||
<el-icon><HomeFilled /></el-icon>
|
||||
<template #title>首页</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
|
||||
<template v-for="menu in sidebarMenus" :key="menu.id">
|
||||
<!-- 有子菜单 -->
|
||||
<el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.path">
|
||||
<template #title>
|
||||
<el-icon><component :is="menu.icon || 'Menu'" /></el-icon>
|
||||
<span>{{ menu.name }}</span>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-for="child in menu.children"
|
||||
:key="child.id"
|
||||
:index="child.path"
|
||||
>
|
||||
<el-icon><component :is="child.icon || 'Document'" /></el-icon>
|
||||
<template #title>{{ child.name }}</template>
|
||||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
<!-- 无子菜单 -->
|
||||
<el-menu-item v-else :index="menu.path">
|
||||
<el-icon><component :is="menu.icon || 'Menu'" /></el-icon>
|
||||
<template #title>{{ menu.name }}</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 主区域 -->
|
||||
@@ -187,17 +189,95 @@ async function handleLogout() {
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 220px;
|
||||
background: linear-gradient(180deg, #0f4a38 0%, #0c3b2e 100%);
|
||||
transition: width 0.3s;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar.collapse {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
/* 折叠态下图标居中优先,不预留滚动槽(此时子菜单以浮层弹出,高度不变化,不会抖动) */
|
||||
.sidebar.collapse .menu-wrapper {
|
||||
scrollbar-gutter: auto;
|
||||
}
|
||||
|
||||
/* 菜单区独立滚动,并始终预留滚动条宽度(scrollbar-gutter: stable):
|
||||
否则展开"基础数据"这类子项较多的目录时,总高度跨过视口,滚动条突然出现/消失,
|
||||
会把菜单横向挤压位移,视觉上就是一卡一卡 */
|
||||
.menu-wrapper {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
scrollbar-gutter: stable;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
|
||||
}
|
||||
|
||||
.menu-wrapper::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.menu-wrapper::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.menu-wrapper::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.menu-wrapper::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.32);
|
||||
}
|
||||
|
||||
/* Element Plus 默认用 transition: height 做展开动画,而 height 过渡不是合成层动画:
|
||||
浏览器每一帧都要重新布局容器内的**全部**子菜单项,子项多时(如"基础数据"10 项)
|
||||
在普通机器上会明显掉帧(实测单帧可达 120ms+)。
|
||||
这里去掉 height 过渡,改用只涉及合成层的 opacity + transform 动画,视觉一样但不触发重排。 */
|
||||
.menu-wrapper :deep(.el-collapse-transition-enter-active),
|
||||
.menu-wrapper :deep(.el-collapse-transition-leave-active) {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
/* 淡入只加在整个子菜单容器上(只产生一个合成层),
|
||||
若加在每个子项上,会为 10 个元素分别创建合成层,展开瞬间反而更慢 */
|
||||
.menu-wrapper :deep(.el-menu--inline) {
|
||||
animation: menu-submenu-in 0.16s ease-out;
|
||||
}
|
||||
|
||||
/* 布局/绘制隔离:展开时把每个菜单项的重排限制在自身内部,避免整块重排 */
|
||||
.menu-wrapper :deep(.el-menu-item),
|
||||
.menu-wrapper :deep(.el-sub-menu__title) {
|
||||
contain: layout paint;
|
||||
}
|
||||
|
||||
/* 收起时不要用 display:none(Element Plus 默认行为),而是用 height:0 + 隐藏裁剪:
|
||||
这样子项在页面加载时就已完成布局,展开瞬间无需对全部子项做首次布局,
|
||||
这正是"子项越多越卡"(基础数据 10 项)的根源所在 */
|
||||
.menu-wrapper :deep(.el-sub-menu:not(.is-opened) > .el-menu--inline) {
|
||||
display: block !important;
|
||||
height: 0 !important;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@keyframes menu-submenu-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
flex: none;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -294,6 +374,8 @@ async function handleLogout() {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
/* 内容区同样预留滚动条宽度,避免切换页面时宽度跳动 */
|
||||
scrollbar-gutter: stable;
|
||||
background: #f0f2f5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -58,6 +58,7 @@ export const componentMap = {
|
||||
'base/yuanliaozhuangkou/index': () => import('../views/base/yuanliaozhuangkou/index.vue'),
|
||||
'base/wuzimulu/index': () => import('../views/base/wuzimulu/index.vue'),
|
||||
'base/gongyingshang/index': () => import('../views/base/gongyingshang/index.vue'),
|
||||
'base/employee/index': () => import('../views/base/employee/index.vue'),
|
||||
'prod/lsjl/index': () => import('../views/prod/lsjl/index.vue'),
|
||||
'prod/xdjy/index': () => import('../views/prod/xdjy/index.vue'),
|
||||
'prod/hbjy/index': () => import('../views/prod/hbjy/index.vue'),
|
||||
|
||||
@@ -36,6 +36,8 @@ function statusType(status) {
|
||||
}
|
||||
|
||||
function handlePageChange(page) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (page === pageIndex.value) return;
|
||||
pageIndex.value = page;
|
||||
loadRecords();
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ function resetSearch() {
|
||||
}
|
||||
|
||||
function handlePageChange(page) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (page === query.pageIndex) return;
|
||||
query.pageIndex = page;
|
||||
load();
|
||||
}
|
||||
|
||||
@@ -79,7 +79,12 @@ async function del(row) {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function handlePageChange(p) { query.pageIndex = p; load(); }
|
||||
function handlePageChange(p) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
load();
|
||||
}
|
||||
onMounted(() => { load(); loadGuige(); });
|
||||
</script>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,13 @@ const form = reactive({
|
||||
|
||||
const vendorGroupTypes = [3, 4]; // 副产品 / 生丝 → 默认分组为"客户"
|
||||
|
||||
// 分页组件挂载时会触发一次 current-change:页码未变化时直接忽略,避免页面首次打开重复请求
|
||||
function handlePageChange(p) {
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
loadList();
|
||||
}
|
||||
|
||||
async function loadList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -190,12 +197,12 @@ onMounted(loadList);
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="query.pageIndex"
|
||||
v-model:page-size="query.pageSize"
|
||||
:current-page="query.pageIndex"
|
||||
:page-size="query.pageSize"
|
||||
:total="total"
|
||||
layout="total, prev, pager, next"
|
||||
class="pager"
|
||||
@current-change="loadList"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="520px">
|
||||
|
||||
@@ -73,7 +73,12 @@ async function del(row) {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function handlePageChange(p) { query.pageIndex = p; load(); }
|
||||
function handlePageChange(p) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
load();
|
||||
}
|
||||
onMounted(load);
|
||||
</script>
|
||||
|
||||
|
||||
@@ -71,7 +71,12 @@ async function del(row) {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function handlePageChange(p) { query.pageIndex = p; load(); }
|
||||
function handlePageChange(p) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
load();
|
||||
}
|
||||
onMounted(() => { load(); loadDepts(); });
|
||||
</script>
|
||||
|
||||
|
||||
@@ -13,18 +13,20 @@ const query = reactive({ pageIndex: 1, pageSize: 20, keyword: '' });
|
||||
const bizTypeOptions = ref(['生产', '辅助']);
|
||||
const sccbFenleiOptions = ref(['无', '管理']);
|
||||
|
||||
// 一次拉取注册表全量后本地取用,避免每个键各发一次请求
|
||||
async function loadRegistryOptions() {
|
||||
try {
|
||||
const load = async (keyName) => {
|
||||
const res = await request.get('/sys/registry/by-key', {
|
||||
params: { category: '基础数据\\工种', keyName }
|
||||
});
|
||||
return (res.data?.value || '')
|
||||
const res = await request.get('/sys/registry');
|
||||
const all = res.data || [];
|
||||
const pick = (keyName) => {
|
||||
const hit = all.find((x) => x.category === '基础数据\\工种' && x.keyName === keyName);
|
||||
return (hit?.value || '')
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
};
|
||||
const [biz, fenlei] = await Promise.all([load('业务类型'), load('生产成本分类')]);
|
||||
const biz = pick('业务类型');
|
||||
const fenlei = pick('生产成本分类');
|
||||
if (biz.length) bizTypeOptions.value = biz;
|
||||
if (fenlei.length) sccbFenleiOptions.value = fenlei;
|
||||
} catch (e) {
|
||||
@@ -52,6 +54,13 @@ const boundRoleIds = ref([]);
|
||||
|
||||
const currentRow = ref(null);
|
||||
|
||||
// 分页组件挂载时会触发一次 current-change:页码未变化时直接忽略,避免页面首次打开重复请求
|
||||
function handlePageChange(p) {
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
loadList();
|
||||
}
|
||||
|
||||
async function loadList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -255,12 +264,12 @@ onMounted(() => {
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="query.pageIndex"
|
||||
v-model:page-size="query.pageSize"
|
||||
:current-page="query.pageIndex"
|
||||
:page-size="query.pageSize"
|
||||
:total="total"
|
||||
layout="total, prev, pager, next"
|
||||
class="pager"
|
||||
@current-change="loadList"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="460px">
|
||||
|
||||
@@ -120,6 +120,13 @@ function handleNodeClick(node) {
|
||||
loadMulu();
|
||||
}
|
||||
|
||||
// 分页组件挂载时会触发一次 current-change:页码未变化时直接忽略,避免页面首次打开重复请求
|
||||
function handlePageChange(p) {
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
loadMulu();
|
||||
}
|
||||
|
||||
async function loadMulu() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -397,12 +404,12 @@ onMounted(loadGroups);
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="query.pageIndex"
|
||||
v-model:page-size="query.pageSize"
|
||||
:current-page="query.pageIndex"
|
||||
:page-size="query.pageSize"
|
||||
:total="total"
|
||||
layout="total, prev, pager, next"
|
||||
class="pager"
|
||||
@current-change="loadMulu"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -49,27 +49,22 @@ function bendiwaidiLabel(v) {
|
||||
return hit ? hit.label : v;
|
||||
}
|
||||
|
||||
// 一次拉取注册表全量后本地取用,避免每个键各发一次请求
|
||||
async function loadRegistryOptions() {
|
||||
const load = async (keyName) => {
|
||||
const res = await request.get('/sys/registry/by-key', {
|
||||
params: { category: '基础数据\\原料庄口', keyName }
|
||||
});
|
||||
return (res.data?.value || '')
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
};
|
||||
try {
|
||||
const [chandi, zhandian, jibie, canpinzhong] = await Promise.all([
|
||||
load('产地'),
|
||||
load('站点'),
|
||||
load('季别'),
|
||||
load('蚕品种')
|
||||
]);
|
||||
registryOptions.chandi = chandi;
|
||||
registryOptions.zhandian = zhandian;
|
||||
registryOptions.jibie = jibie;
|
||||
registryOptions.canpinzhong = canpinzhong;
|
||||
const res = await request.get('/sys/registry');
|
||||
const all = res.data || [];
|
||||
const pick = (keyName) => {
|
||||
const hit = all.find((x) => x.category === '基础数据\\原料庄口' && x.keyName === keyName);
|
||||
return (hit?.value || '')
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
};
|
||||
registryOptions.chandi = pick('产地');
|
||||
registryOptions.zhandian = pick('站点');
|
||||
registryOptions.jibie = pick('季别');
|
||||
registryOptions.canpinzhong = pick('蚕品种');
|
||||
} catch (e) {
|
||||
// 注册表未配置时下拉为空,仍可手工录入
|
||||
}
|
||||
@@ -82,6 +77,13 @@ async function loadWuziOptions() {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 分页组件挂载时会触发一次 current-change:页码未变化时直接忽略,避免页面首次打开重复请求
|
||||
function handlePageChange(p) {
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
loadList();
|
||||
}
|
||||
|
||||
async function loadList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -274,12 +276,12 @@ onMounted(async () => {
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="query.pageIndex"
|
||||
v-model:page-size="query.pageSize"
|
||||
:current-page="query.pageIndex"
|
||||
:page-size="query.pageSize"
|
||||
:total="total"
|
||||
layout="total, prev, pager, next"
|
||||
class="pager"
|
||||
@current-change="loadList"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px">
|
||||
|
||||
@@ -48,6 +48,13 @@ function defaultRange() {
|
||||
return { start: str(start), end: str(end) };
|
||||
}
|
||||
|
||||
// 分页组件挂载时会触发一次 current-change:页码未变化时直接忽略,避免页面首次打开重复请求
|
||||
function handlePageChange(p) {
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
loadList();
|
||||
}
|
||||
|
||||
async function loadList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -205,12 +212,12 @@ onMounted(loadList);
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="query.pageIndex"
|
||||
v-model:page-size="query.pageSize"
|
||||
:current-page="query.pageIndex"
|
||||
:page-size="query.pageSize"
|
||||
:total="total"
|
||||
layout="total, prev, pager, next"
|
||||
class="pager"
|
||||
@current-change="loadList"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="480px">
|
||||
|
||||
@@ -80,7 +80,12 @@ async function del(row) {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function handlePageChange(p) { query.pageIndex = p; load(); }
|
||||
function handlePageChange(p) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
load();
|
||||
}
|
||||
onMounted(load);
|
||||
</script>
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ const userStore = useUserStore();
|
||||
const user = userStore.userInfo || {};
|
||||
|
||||
const quickLinks = [
|
||||
{ title: '落丝记录', desc: '缫丝生产 · 落丝管理', icon: 'DataLine', path: '/prod/lsjl', color: '#1e6b52' },
|
||||
{ title: '纤度检验', desc: '纤度 / 野纤等级判定', icon: 'ScaleToOriginal', path: '/prod/xdjy', color: '#c9a54a' },
|
||||
{ title: '黑板检验', desc: '清洁 / 洁净等级', icon: 'Grid', path: '/prod/hbjy', color: '#3f8f6e' },
|
||||
{ title: '落丝记录', desc: '前缫 · 落丝管理', icon: 'DataLine', path: '/prod/qianxian/lsjl', color: '#1e6b52' },
|
||||
{ title: '纤度检验', desc: '后缫 · 纤度 / 野纤等级判定', icon: 'ScaleToOriginal', path: '/prod/houxian/xdjy', color: '#c9a54a' },
|
||||
{ title: '黑板检验', desc: '后缫 · 清洁 / 洁净等级', icon: 'Grid', path: '/prod/houxian/hbjy', color: '#3f8f6e' },
|
||||
{ title: '考勤打卡', desc: '上下班签到签退', icon: 'AlarmClock', path: '/attendance/punch', color: '#b8873a' }
|
||||
];
|
||||
|
||||
|
||||
@@ -64,7 +64,12 @@ async function markAllRead() {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function handlePageChange(p) { query.pageIndex = p; load(); }
|
||||
function handlePageChange(p) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
load();
|
||||
}
|
||||
function resetPage() { query.pageIndex = 1; load(); }
|
||||
|
||||
function rowClass({ row }) {
|
||||
|
||||
@@ -31,7 +31,12 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
function handlePageChange(p) { query.pageIndex = p; load(); }
|
||||
function handlePageChange(p) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
load();
|
||||
}
|
||||
|
||||
// ==================== 编辑对话框 ====================
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
@@ -124,7 +124,12 @@ async function del(row) {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function handlePageChange(p) { query.pageIndex = p; load(); }
|
||||
function handlePageChange(p) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
load();
|
||||
}
|
||||
|
||||
onMounted(() => { load(); loadDepts(); loadZhuangkou(); loadGuige(); });
|
||||
</script>
|
||||
|
||||
@@ -32,7 +32,12 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
function handlePageChange(p) { query.pageIndex = p; load(); }
|
||||
function handlePageChange(p) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (p === query.pageIndex) return;
|
||||
query.pageIndex = p;
|
||||
load();
|
||||
}
|
||||
|
||||
// ==================== 编辑对话框 ====================
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
@@ -138,7 +138,12 @@ async function handleSaveRoles() {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function handlePageChange(page) { query.page = page; loadList(); }
|
||||
function handlePageChange(page) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (page === query.page) return;
|
||||
query.page = page;
|
||||
loadList();
|
||||
}
|
||||
|
||||
onMounted(() => { loadList(); loadDepts(); loadRoles(); });
|
||||
</script>
|
||||
|
||||
@@ -128,6 +128,8 @@ async function handleResetPwd(row) {
|
||||
}
|
||||
|
||||
function handlePageChange(page) {
|
||||
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
|
||||
if (page === query.pageIndex) return;
|
||||
query.pageIndex = page;
|
||||
loadList();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ export default defineConfig({
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
port: 5173,
|
||||
// 注意:这里刻意不做 server.warmup 全量预热。
|
||||
// 页面组件一律按需加载:只有点进具体菜单项时,才编译并加载对应页面组件。
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3000',
|
||||
|
||||
Reference in New Issue
Block a user