重构页面样式
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled

This commit is contained in:
cjh
2026-06-04 11:12:09 +08:00
parent 5fc8580f93
commit dca4521b35
30 changed files with 5562 additions and 540 deletions

View File

@@ -2,6 +2,16 @@ import { useRouter } from 'vue-router';
import type { RouteLocationRaw } from 'vue-router';
import type { RouteKey } from '@elegant-router/types';
import { router as globalRouter } from '@/router';
import { useRouteStore } from '@/store/modules/route';
function findMenuByKey(menus: App.Global.Menu[], key: string): App.Global.Menu | null {
for (const menu of menus) {
if (menu.key === key) return menu;
const child = findMenuByKey(menu.children || [], key);
if (child) return child;
}
return null;
}
/**
* Router push
@@ -38,7 +48,24 @@ export function useRouterPush(inSetup = true) {
function routerPushByKeyWithMetaQuery(key: RouteKey) {
const allRoutes = router.getRoutes();
const meta = allRoutes.find(item => item.name === key)?.meta || null;
let targetRoute = allRoutes.find(item => item.name === key);
if (!targetRoute) {
const routeStore = useRouteStore();
const menu = findMenuByKey(routeStore.menus, key);
targetRoute = allRoutes.find(item => item.name === menu?.routeKey);
if (!targetRoute && menu?.routePath) {
return routerPush(menu.routePath);
}
}
if (!targetRoute) {
console.warn(`[router] route key "${key}" not found`);
return Promise.resolve();
}
const meta = targetRoute?.meta || null;
const query: Record<string, string> = {};
@@ -46,7 +73,7 @@ export function useRouterPush(inSetup = true) {
query[item.key] = item.value;
});
return routerPushByKey(key, { query });
return routerPushByKey(targetRoute.name as RouteKey, { query });
}
async function toHome() {

View File

@@ -206,6 +206,18 @@ const local: App.I18n.Schema = {
'iframe-page': 'Iframe',
home: 'Home',
system: 'System Management',
system2: 'System Management 2',
system2_user: 'User Management 2',
system2_role: 'Role Management 2',
system2_menu: 'Menu Management 2',
system2_dept: 'Dept Management 2',
system2_post: 'Post Management 2',
system2_dict: 'Dict Management 2',
system2_config: 'Config Management 2',
system2_client: 'Client Management 2',
system2_notice: 'Notice Management 2',
system2_oss: 'File Management 2',
system2_log: 'Log Center 2',
system_menu: 'Menu Management',
tool: 'System Tools',
tool_gen: 'Code Generation',

View File

@@ -206,6 +206,18 @@ const local: App.I18n.Schema = {
'iframe-page': '外链页面',
home: '首页',
system: '系统管理',
system2: '系统管理2',
system2_user: '用户管理2',
system2_role: '角色管理2',
system2_menu: '菜单管理2',
system2_dept: '部门管理2',
system2_post: '岗位管理2',
system2_dict: '字典管理2',
system2_config: '参数设置2',
system2_client: '客户端管理2',
system2_notice: '通知公告2',
system2_oss: '文件管理2',
system2_log: '日志中心2',
system_menu: '菜单管理',
tool: '系统工具',
tool_gen: '代码生成',

View File

@@ -74,5 +74,16 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
"system_tenant-package": () => import("@/views/system/tenant-package/index.vue"),
system_tenant: () => import("@/views/system/tenant/index.vue"),
system_user: () => import("@/views/system/user/index.vue"),
system2_client: () => import("@/views/system2/client/index.vue"),
system2_config: () => import("@/views/system2/config/index.vue"),
system2_dept: () => import("@/views/system2/dept/index.vue"),
system2_dict: () => import("@/views/system2/dict/index.vue"),
system2_log: () => import("@/views/system2/log/index.vue"),
system2_menu: () => import("@/views/system2/menu/index.vue"),
system2_notice: () => import("@/views/system2/notice/index.vue"),
system2_oss: () => import("@/views/system2/oss/index.vue"),
system2_post: () => import("@/views/system2/post/index.vue"),
system2_role: () => import("@/views/system2/role/index.vue"),
system2_user: () => import("@/views/system2/user/index.vue"),
tool_gen: () => import("@/views/tool/gen/index.vue"),
};

View File

@@ -695,6 +695,121 @@ export const generatedRoutes: GeneratedRoute[] = [
}
]
},
{
name: 'system2',
path: '/system2',
component: 'layout.base',
redirect: {
name: 'system2_user'
},
meta: {
title: 'system2',
i18nKey: 'route.system2',
localIcon: 'menu-system',
order: 2
},
children: [
{
name: 'system2_client',
path: '/system2/client',
component: 'view.system2_client',
meta: {
title: 'system2_client',
i18nKey: 'route.system2_client'
}
},
{
name: 'system2_config',
path: '/system2/config',
component: 'view.system2_config',
meta: {
title: 'system2_config',
i18nKey: 'route.system2_config'
}
},
{
name: 'system2_dept',
path: '/system2/dept',
component: 'view.system2_dept',
meta: {
title: 'system2_dept',
i18nKey: 'route.system2_dept'
}
},
{
name: 'system2_dict',
path: '/system2/dict',
component: 'view.system2_dict',
meta: {
title: 'system2_dict',
i18nKey: 'route.system2_dict'
}
},
{
name: 'system2_log',
path: '/system2/log',
component: 'view.system2_log',
meta: {
title: 'system2_log',
i18nKey: 'route.system2_log'
}
},
{
name: 'system2_menu',
path: '/system2/menu',
component: 'view.system2_menu',
meta: {
title: 'system2_menu',
i18nKey: 'route.system2_menu'
}
},
{
name: 'system2_notice',
path: '/system2/notice',
component: 'view.system2_notice',
meta: {
title: 'system2_notice',
i18nKey: 'route.system2_notice'
}
},
{
name: 'system2_oss',
path: '/system2/oss',
component: 'view.system2_oss',
meta: {
title: 'system2_oss',
i18nKey: 'route.system2_oss'
}
},
{
name: 'system2_post',
path: '/system2/post',
component: 'view.system2_post',
meta: {
title: 'system2_post',
i18nKey: 'route.system2_post'
}
},
{
name: 'system2_role',
path: '/system2/role',
component: 'view.system2_role',
meta: {
title: 'system2_role',
i18nKey: 'route.system2_role'
}
},
{
name: 'system2_user',
path: '/system2/user',
component: 'view.system2_user',
meta: {
title: 'system2_user',
i18nKey: 'route.system2_user'
}
}
]
},
{
name: 'tool',
path: '/tool',

View File

@@ -233,6 +233,18 @@ const routeMap: RouteMap = {
"system_tenant": "/system/tenant",
"system_tenant-package": "/system/tenant-package",
"system_user": "/system/user",
"system2": "/system2",
"system2_client": "/system2/client",
"system2_config": "/system2/config",
"system2_dept": "/system2/dept",
"system2_dict": "/system2/dict",
"system2_log": "/system2/log",
"system2_menu": "/system2/menu",
"system2_notice": "/system2/notice",
"system2_oss": "/system2/oss",
"system2_post": "/system2/post",
"system2_role": "/system2/role",
"system2_user": "/system2/user",
"tool": "/tool",
"tool_gen": "/tool/gen",
"user-center": "/user-center"

View File

@@ -139,6 +139,85 @@ const dynamicSupplementAuthRoutes: ElegantConstRoute[] = [
hideInMenu: true,
activeMenu: 'smart-proposal_tech-proposal'
}
},
{
name: 'system2',
path: '/system2',
component: 'layout.base',
redirect: { name: 'system2_user' },
meta: {
title: 'system2',
i18nKey: 'route.system2',
hideInMenu: true
},
children: [
{
name: 'system2_user',
path: '/system2/user',
component: 'view.system2_user',
meta: { title: 'system2_user', i18nKey: 'route.system2_user', hideInMenu: true }
},
{
name: 'system2_role',
path: '/system2/role',
component: 'view.system2_role',
meta: { title: 'system2_role', i18nKey: 'route.system2_role', hideInMenu: true }
},
{
name: 'system2_menu',
path: '/system2/menu',
component: 'view.system2_menu',
meta: { title: 'system2_menu', i18nKey: 'route.system2_menu', hideInMenu: true }
},
{
name: 'system2_dept',
path: '/system2/dept',
component: 'view.system2_dept',
meta: { title: 'system2_dept', i18nKey: 'route.system2_dept', hideInMenu: true }
},
{
name: 'system2_post',
path: '/system2/post',
component: 'view.system2_post',
meta: { title: 'system2_post', i18nKey: 'route.system2_post', hideInMenu: true }
},
{
name: 'system2_dict',
path: '/system2/dict',
component: 'view.system2_dict',
meta: { title: 'system2_dict', i18nKey: 'route.system2_dict', hideInMenu: true }
},
{
name: 'system2_config',
path: '/system2/config',
component: 'view.system2_config',
meta: { title: 'system2_config', i18nKey: 'route.system2_config', hideInMenu: true }
},
{
name: 'system2_client',
path: '/system2/client',
component: 'view.system2_client',
meta: { title: 'system2_client', i18nKey: 'route.system2_client', hideInMenu: true }
},
{
name: 'system2_notice',
path: '/system2/notice',
component: 'view.system2_notice',
meta: { title: 'system2_notice', i18nKey: 'route.system2_notice', hideInMenu: true }
},
{
name: 'system2_oss',
path: '/system2/oss',
component: 'view.system2_oss',
meta: { title: 'system2_oss', i18nKey: 'route.system2_oss', hideInMenu: true }
},
{
name: 'system2_log',
path: '/system2/log',
component: 'view.system2_log',
meta: { title: 'system2_log', i18nKey: 'route.system2_log', hideInMenu: true }
}
]
}
];

View File

@@ -43,9 +43,10 @@ export function fetchBatchDeleteDept(deptIds: CommonType.IdType[]) {
}
/** 获取部门选择框列表 */
export function fetchGetDeptSelect() {
export function fetchGetDeptSelect(deptIds?: CommonType.IdType[]) {
return request<Api.System.Dept[]>({
url: '/system/dept/optionselect',
method: 'get'
method: 'get',
params: { deptIds }
});
}

View File

@@ -87,6 +87,18 @@ declare module "@elegant-router/types" {
"system_tenant": "/system/tenant";
"system_tenant-package": "/system/tenant-package";
"system_user": "/system/user";
"system2": "/system2";
"system2_client": "/system2/client";
"system2_config": "/system2/config";
"system2_dept": "/system2/dept";
"system2_dict": "/system2/dict";
"system2_log": "/system2/log";
"system2_menu": "/system2/menu";
"system2_notice": "/system2/notice";
"system2_oss": "/system2/oss";
"system2_post": "/system2/post";
"system2_role": "/system2/role";
"system2_user": "/system2/user";
"tool": "/tool";
"tool_gen": "/tool/gen";
"user-center": "/user-center";
@@ -142,6 +154,7 @@ declare module "@elegant-router/types" {
| "social-callback"
| "statistical-analysis"
| "system"
| "system2"
| "tool"
| "user-center"
>;
@@ -220,6 +233,17 @@ declare module "@elegant-router/types" {
| "system_tenant-package"
| "system_tenant"
| "system_user"
| "system2_client"
| "system2_config"
| "system2_dept"
| "system2_dict"
| "system2_log"
| "system2_menu"
| "system2_notice"
| "system2_oss"
| "system2_post"
| "system2_role"
| "system2_user"
| "tool_gen"
>;

View File

@@ -169,8 +169,8 @@ watch(fileList, value => {
<div class="watermark" aria-hidden="true"></div>
<div class="contain-wrapper">
<button class="history-button" type="button" @click="openHistoryList">
<SvgIcon icon="material-symbols:history-rounded" />
历史记录
<span class="history-clock" aria-hidden="true"></span>
<span class="history-text">历史记录</span>
</button>
<section class="hero-panel">
@@ -317,10 +317,26 @@ watch(fileList, value => {
line-height: 1;
}
.history-button :deep(.svg-icon) {
width: 16px;
height: 16px;
.history-button::before,
.history-button::after {
display: none !important;
content: none !important;
}
.history-button :deep(svg),
.history-button :deep(.svg-icon),
.history-button :deep(.iconify) {
display: none !important;
}
.history-clock {
color: #20242d;
font-size: 16px;
line-height: 1;
}
.history-text {
line-height: 1;
}
.hero-panel {

View File

@@ -14,7 +14,6 @@ const {
detailFixedCount,
detailIssueCount,
detailLoading,
detailPageCount,
detailPagination,
detailRowProps,
detailSelectedRowId,
@@ -276,7 +275,6 @@ const {
v-model:page-size="detailPagination.pageSize"
class="detail-pagination"
:item-count="detailTotal"
:page-count="detailPageCount"
:page-sizes="[20, 50]"
show-size-picker
show-quick-jumper

File diff suppressed because it is too large Load Diff

View File

@@ -7,25 +7,50 @@ const {
analysisProposalFileIds,
analysisProposalOptions,
analysisReferenceData,
analysisResultColumns,
analysisResultData,
analysisResultLoading,
analysisRuleJsonSetting,
analysisScopeOptions,
analysisStat,
btnLoading,
deleteAnalysisFile,
exportAnalysisResult,
openAnalysisInfo,
openAnalysisSmartFilter,
reAnalysisRegularAnalysis,
restoreAnalysisDocument,
rewriteRegularAnalysis,
startRegularAnalysis
} = useTechProposalRedesignContext();
const toggleAnalysisCheckedRow = (row: any, checked: boolean) => {
const key = row.id;
analysisCheckedRowKeys.value = checked
? Array.from(new Set([...analysisCheckedRowKeys.value, key]))
: analysisCheckedRowKeys.value.filter((item: any) => item !== key);
};
const isAnalysisChecked = (row: any) => analysisCheckedRowKeys.value.includes(row.id);
const getAnalysisStatusClass = (status?: string) => {
if (status?.includes('完成')) return 'success';
if (status?.includes('正在')) return 'pending';
if (status?.includes('失败')) return 'failed';
return '';
};
</script>
<template>
<div class="regular-analysis-workbench">
<section class="regular-config-panel">
<header class="regular-config-toolbar">
<div class="regular-panel-title">
<span class="regular-title-marker"></span>
<div>
<strong>纪律性分析规则</strong>
<p>选择参照与目标文件按文本图片文件属性维度识别雷同风险</p>
</div>
</div>
<button class="review-start-check" type="button" :disabled="btnLoading" @click="startRegularAnalysis">
{{ btnLoading ? '分析中' : '开始分析' }}
</button>
@@ -43,6 +68,7 @@ const {
label-field="name"
value-field="id"
children-field="dtlList"
to="body"
:options="analysisProposalOptions"
/>
</label>
@@ -56,63 +82,66 @@ const {
label-field="name"
value-field="id"
children-field="dtlList"
to="body"
:options="analysisProposalOptions"
/>
</label>
</div>
<section class="regular-setting-card design-card">
<header>
<strong>文本</strong>
<span>TEXT</span>
</header>
<div class="regular-inline-rule design-inline-rule">
<NCheckbox v-model:checked="analysisRuleJsonSetting.checkDuplicateContentEnable">重复内容</NCheckbox>
<span>&gt;=</span>
<NSelect
v-model:value="analysisRuleJsonSetting.checkDuplicateContent"
:options="analysisPercentOptions"
size="small"
/>
<span></span>
<NSelect
v-model:value="analysisRuleJsonSetting.splitParagraphs"
:options="analysisScopeOptions"
size="small"
/>
</div>
<div class="regular-ai-line">
<NCheckbox v-model:checked="analysisRuleJsonSetting.keyInformation">重点信息</NCheckbox>
<em>AI</em>
</div>
<div class="regular-ai-line">
<NCheckbox v-model:checked="analysisRuleJsonSetting.smartFilterEnable">智能过滤</NCheckbox>
<button type="button" @click="openAnalysisSmartFilter">设置</button>
<em>AI</em>
</div>
</section>
<div class="regular-rule-grid">
<section class="regular-setting-card design-card featured">
<header>
<strong>文本</strong>
<span>TEXT</span>
</header>
<div class="regular-inline-rule design-inline-rule">
<NCheckbox v-model:checked="analysisRuleJsonSetting.checkDuplicateContentEnable">重复内容</NCheckbox>
<span>&gt;=</span>
<NSelect
v-model:value="analysisRuleJsonSetting.checkDuplicateContent"
:options="analysisPercentOptions"
size="small"
/>
<span></span>
<NSelect
v-model:value="analysisRuleJsonSetting.splitParagraphs"
:options="analysisScopeOptions"
size="small"
/>
</div>
<div class="regular-ai-line">
<NCheckbox v-model:checked="analysisRuleJsonSetting.keyInformation">重点信息</NCheckbox>
<em>AI</em>
</div>
<div class="regular-ai-line">
<NCheckbox v-model:checked="analysisRuleJsonSetting.smartFilterEnable">智能过滤</NCheckbox>
<button type="button" @click="openAnalysisSmartFilter">设置</button>
<em>AI</em>
</div>
</section>
<section class="regular-setting-card design-card">
<header>
<strong>图片</strong>
<span>IMAGE</span>
</header>
<NCheckbox v-model:checked="analysisRuleJsonSetting.image.similar">相似图片</NCheckbox>
<div class="regular-ai-line">
<NCheckbox v-model:checked="analysisRuleJsonSetting.image.sameText">图片中相同文字及重点信息</NCheckbox>
<em>AI</em>
</div>
</section>
<section class="regular-setting-card design-card">
<header>
<strong>图片</strong>
<span>IMAGE</span>
</header>
<NCheckbox v-model:checked="analysisRuleJsonSetting.image.similar">相似图片</NCheckbox>
<div class="regular-ai-line">
<NCheckbox v-model:checked="analysisRuleJsonSetting.image.sameText">图片中相同文字及重点信息</NCheckbox>
<em>AI</em>
</div>
</section>
<section class="regular-setting-card design-card compact-card">
<header>
<strong>文件属性</strong>
<span>METADATA</span>
</header>
<NCheckbox v-model:checked="analysisRuleJsonSetting.checkFileProperties">
相同作者最后一次保存者及公司
</NCheckbox>
</section>
<section class="regular-setting-card design-card compact-card">
<header>
<strong>文件属性</strong>
<span>METADATA</span>
</header>
<NCheckbox v-model:checked="analysisRuleJsonSetting.checkFileProperties">
相同作者最后一次保存者及公司
</NCheckbox>
</section>
</div>
</div>
</section>
@@ -130,30 +159,106 @@ const {
已修复
<strong>{{ analysisStat.rewriteDocCount }}</strong>
</div>
<div class="regular-design-actions">
<button type="button" @click="rewriteRegularAnalysis">一键改写</button>
<button type="button" @click="restoreAnalysisDocument">还原文档</button>
<button type="button" @click="exportAnalysisResult">导出文档</button>
</div>
</header>
<div class="regular-result-area">
<div v-if="!analysisResultLoading && analysisResultData.length === 0" class="regular-empty-result">
<strong>暂无检查结果</strong>
<p>点击上方 开始分析 后生成结果</p>
</div>
<div v-else class="regular-result-scroll">
<NDataTable
v-model:checked-row-keys="analysisCheckedRowKeys"
:row-key="(row: any) => row.id"
:columns="analysisResultColumns"
:data="analysisResultData"
:bordered="false"
:loading="analysisResultLoading"
:single-line="false"
:scroll-x="1124"
class="regular-data-table regular-result-detail-table"
/>
</div>
<div class="regular-result-area design-result-stack">
<section class="design-table-block regular-reference-block">
<header>
<strong>参照投标文件</strong>
<button
class="regular-reanalyze-button"
type="button"
:disabled="btnLoading || analysisResultData.length <= 0"
@click="reAnalysisRegularAnalysis"
>
{{ btnLoading ? '分析中' : '重新分析' }}
</button>
</header>
<div class="design-table-scroll">
<table class="design-reference-table">
<thead>
<tr>
<th>序号</th>
<th>参照单位</th>
<th>参照文件名称</th>
<th>更新时间</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in analysisReferenceData" :key="`${item.proposalDtlId1 || item.id}-${index}`">
<td>{{ index + 1 }}</td>
<td>{{ item.proposal1Name || '-' }}</td>
<td>{{ item.proposalDtl1Name || '-' }}</td>
<td>{{ item.updateTime || '-' }}</td>
</tr>
<tr v-if="!analysisReferenceData.length">
<td colspan="4" class="design-table-empty">暂无参照文件</td>
</tr>
</tbody>
</table>
</div>
</section>
<section class="design-table-block regular-analysis-result-block">
<header>
<strong>分析结果详情</strong>
<div class="regular-design-actions">
<button type="button" @click="rewriteRegularAnalysis">一键改写</button>
<button type="button" @click="restoreAnalysisDocument">还原文档</button>
<button type="button" @click="exportAnalysisResult">导出文档</button>
</div>
</header>
<div v-if="!analysisResultLoading && analysisResultData.length === 0" class="regular-empty-result">
<strong>暂无检查结果</strong>
<p>点击左侧 开始分析 后生成结果</p>
</div>
<div v-else class="regular-result-scroll">
<table class="design-analysis-table">
<thead>
<tr>
<th></th>
<th>序号</th>
<th>目标单位</th>
<th>风险度</th>
<th>文本相似度(%)</th>
<th>图片相似度(%)</th>
<th>文件属性雷同</th>
<th>重点信息雷同()</th>
<th>检查状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in analysisResultData" :key="item.id">
<td>
<input
type="checkbox"
:checked="isAnalysisChecked(item)"
@change="toggleAnalysisCheckedRow(item, ($event.target as HTMLInputElement).checked)"
/>
</td>
<td>{{ index + 1 }}</td>
<td>{{ item.proposal2Name || '-' }}</td>
<td>
<strong class="analysis-risk-value">{{ item.riskDegree ?? 0 }}</strong>
</td>
<td>{{ item.textSimilarity ?? 0 }}</td>
<td>{{ item.imgSimilarity ?? 0 }}</td>
<td>{{ item.docSimilarity ?? 0 }}</td>
<td>{{ item.informationSimilarity ?? 0 }}</td>
<td>
<span class="analysis-status" :class="getAnalysisStatusClass(item.taskStatus)">
{{ item.taskStatus || '未审查' }}
</span>
</td>
<td class="design-analysis-actions-cell">
<button type="button" @click.stop="openAnalysisInfo(item, true)">查看详情</button>
<button class="danger" type="button" @click.stop="deleteAnalysisFile(item.proposalDtlId2)">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</section>
</div>

View File

@@ -2,7 +2,6 @@
import { useTechProposalRedesignContext } from '../context';
const {
appStore,
batchDeleteResponseModule,
btnLoading,
collapseAllResponseRules,
@@ -19,18 +18,20 @@ const {
responseGenerateLoading,
responseHistoryBidding,
responseHistoryCards,
responseCheckedKeys,
responseResultCompanyColumns,
responseResultLoading,
responseResultScrollX,
responseResultTableRows,
responseReviewStatus,
responseRuleTableRows,
responseSourceTab,
responseStartCheck,
responseStatisticData,
saveResponseRuleData,
selectedResponseDocName,
toggleResponseRuleExpand,
updateResponseCheckedKeys
toggleResponseCheckedKey,
toggleResponseRuleExpand
} = useTechProposalRedesignContext();
</script>
@@ -156,7 +157,11 @@ const {
{{ row.expanded ? '⌄' : '〉' }}
</button>
<label>
<input type="checkbox" checked @change="updateResponseCheckedKeys([row.id])" />
<input
type="checkbox"
:checked="responseCheckedKeys.includes(row.id)"
@change="toggleResponseCheckedKey(row.id, ($event.target as HTMLInputElement).checked)"
/>
{{ row.name }}
</label>
<p v-if="row.scoringStandard" class="response-rule-desc">
@@ -195,7 +200,10 @@ const {
</div>
</header>
<div class="response-result-table">
<div v-if="responseResultTableRows.length > 0" class="response-result-native-scroll">
<div
v-if="responseResultTableRows.length > 0 && !responseReviewStatus.includes('未审查')"
class="response-result-native-scroll"
>
<table class="review-response-result-table" :style="{ minWidth: `${responseResultScrollX}px` }">
<thead>
<tr>
@@ -216,12 +224,18 @@ const {
<span v-if="row[column.key] === true" class="response-pass-dot"></span>
<span v-else-if="row[column.key] === false" class="response-fail-dot">×</span>
</td>
<td><span class="response-fail-pill">{{ row.taskStatus || '审查失败' }}</span></td>
<td><span class="response-fail-pill">{{ row.taskStatus || responseReviewStatus }}</span></td>
</tr>
</tbody>
</table>
</div>
<NEmpty v-if="!responseResultLoading && responseResultTableRows.length === 0" description="暂无检查结果" />
<div
v-if="!responseResultLoading && (responseResultTableRows.length === 0 || responseReviewStatus.includes('未审查'))"
class="response-result-empty-state"
>
<strong>暂无检查结果</strong>
<p>点击上方开始检查后生成结果</p>
</div>
</div>
</section>
</div>
@@ -234,6 +248,29 @@ const {
overflow: auto;
}
.response-result-empty-state {
display: grid;
min-height: 72px;
place-items: center;
border: 1px dashed #d7dfec;
border-radius: 8px;
color: #6b7485;
margin: 8px;
padding: 12px;
text-align: center;
}
.response-result-empty-state strong {
color: #2e3543;
font-size: 14px;
}
.response-result-empty-state p {
margin: 8px 0 0;
color: #7a8394;
font-size: 13px;
}
.review-response-result-table {
width: 100%;
border-collapse: collapse;

View File

@@ -55,17 +55,9 @@ const back = () => {
</script>
<template>
<NFlex vertical :size="[0, 20]" class="contain h-full w-full bg-#F1F2F6">
<div class="contain-header flex items-center flex-justify-start bg-white">
<div class="flex cursor-pointer items-center px-25px py-12px" @click="back">
<NButton text>
<NIcon class="text-21px">
<icon-local-back-icon class="block text-21px" />
</NIcon>
</NButton>
<NText class="ml-2 text-3.5 color-#333333">返回上一步</NText>
</div>
<div class="contain-header-tab ml-40px h-100% flex">
<NFlex vertical :size="[0, 0]" class="contain h-full w-full bg-#f6f8fc">
<div class="contain-header flex items-center justify-between bg-white">
<div class="contain-header-tab h-100% flex">
<div
v-for="item in tabList"
:key="item.value"
@@ -76,6 +68,9 @@ const back = () => {
<NText :class="item.value === currentTab ? 'text-#1e5ef9' : 'text-#333'">{{ item.label }}</NText>
</div>
</div>
<div class="contain-header-actions">
<button class="cancel" type="button" @click="back">取消</button>
</div>
</div>
<div class="contain-main flex-1">
<div class="contain-main-wrapper h-100% w-100%">
@@ -106,19 +101,233 @@ const back = () => {
<style lang="scss" scoped>
.contain {
padding: 0;
overflow: hidden;
&-header {
box-shadow: 0rem 0.13rem 0.25rem rgba(122, 122, 122, 0.25);
height: 50px;
flex: 0 0 50px;
border-bottom: 1px solid #dfe6f2;
background: #fffaf4 !important;
box-shadow: none;
padding: 0 18px 0 40px;
&-tab {
.active-item {
background-color: rgba($color: #1e5ef9, $alpha: 0.1);
position: relative;
background-color: transparent;
font-weight: 700;
&::after {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 2px;
background: #1e5ef9;
content: '';
}
}
}
&-tab-item {
min-width: 64px;
justify-content: center;
padding: 0 18px !important;
font-size: 14px;
}
&-actions {
display: inline-flex;
align-items: center;
gap: 10px;
button {
min-width: 64px;
height: 32px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 700;
padding: 0 16px;
}
.cancel {
border: 1px solid #ffd9a9;
background: #fff5e8;
color: #bd6a18;
}
}
}
&-main {
min-height: 0;
overflow: hidden;
padding: 14px 10px 16px;
background: #f6f8fc;
}
}
:deep(.module) {
height: 100% !important;
padding-bottom: 0 !important;
overflow: hidden !important;
}
:deep(.module-wrapper) {
box-sizing: border-box;
height: 100% !important;
gap: 14px !important;
padding: 0 14px !important;
}
:deep(.module-wrapper-sider) {
width: 230px !important;
flex: 0 0 230px !important;
border: 1px solid #dbe3ef;
border-radius: 4px !important;
background: #fff !important;
overflow: hidden;
}
:deep(.module-wrapper-sider-search) {
padding: 14px 14px 10px !important;
}
:deep(.module-wrapper-sider-search .n-input) {
--n-height: 32px !important;
--n-border-radius: 6px !important;
--n-border: 1px solid #dbe3ef !important;
--n-border-hover: 1px solid #b8c8e6 !important;
--n-border-focus: 1px solid #2d66ff !important;
--n-box-shadow-focus: none !important;
background: #fff !important;
box-shadow: none !important;
}
:deep(.module-wrapper-sider-header) {
height: 104px !important;
border-bottom: 1px solid #e8edf5;
border-radius: 0 !important;
background: #eef5ff !important;
background-image: none !important;
padding: 14px 10px !important;
}
:deep(.module-wrapper-sider-content) {
margin-top: 0 !important;
overflow: hidden !important;
}
:deep(.module-wrapper-sider-content .n-card) {
border-radius: 0 !important;
background: #fff !important;
}
:deep(.module-wrapper-sider-content .n-card-header) {
min-height: 42px;
border-bottom: 1px solid #e8edf5;
padding: 0 10px !important;
}
:deep(.module-wrapper-sider-content .n-card-header__main) {
color: #243044 !important;
font-size: 14px !important;
font-weight: 800 !important;
}
:deep(.module-wrapper-sider-content .n-card__content) {
padding: 0 !important;
}
:deep(.module-wrapper-sider-content .n-data-table-th) {
height: 36px;
background: #f7f8fb !important;
border-bottom: 1px solid #e8edf5 !important;
color: #0f1e36 !important;
font-weight: 800 !important;
}
:deep(.module-wrapper-sider-content .n-data-table-td) {
height: 34px;
border-bottom: 1px solid #edf1f6 !important;
color: #0f1e36 !important;
}
:deep(.module-wrapper-sider-content .selected-row),
:deep(.module-wrapper-sider-content .selected-row td) {
background: #eaf2ff !important;
color: #1f62ff !important;
}
:deep(.module-wrapper-content) {
min-width: 0;
flex: 1 1 0 !important;
width: auto !important;
border: 1px solid #dbe3ef;
border-radius: 0 !important;
background: #fff !important;
overflow: hidden;
}
:deep(.module-wrapper-content-card) {
border-radius: 0 !important;
}
:deep(.module-wrapper-content-card-header) {
height: 34px !important;
border-bottom: 1px solid #e8edf5 !important;
background: #fff !important;
padding-left: 76px !important;
}
:deep(.module-wrapper-content-card-header .n-text) {
color: #0f1e36 !important;
font-size: 14px !important;
font-weight: 800 !important;
}
:deep(.module-wrapper-content-card .gradient-1::before) {
width: auto !important;
height: 24px !important;
line-height: 24px !important;
top: 5px !important;
left: 10px !important;
border-radius: 4px !important;
background: linear-gradient(180deg, #5f90ff 0%, #3064df 100%) !important;
padding: 0 8px;
}
:deep(.module-wrapper-content-card .gradient-2::before) {
width: auto !important;
height: 24px !important;
line-height: 24px !important;
top: 5px !important;
left: 10px !important;
border-radius: 4px !important;
background: linear-gradient(180deg, #ffbe62 0%, #ff8d1f 100%) !important;
padding: 0 8px;
}
:deep(.module-wrapper-content-card-content) {
margin-top: 0 !important;
}
:deep(.module-wrapper-content-card-content-title) {
height: 34px;
border-bottom: 1px solid #eef2f7;
background: #fff !important;
padding: 0 10px !important;
color: #5e6777;
font-size: 12px;
}
:deep(.module-wrapper-content-card-content-body) {
border-radius: 0 !important;
background: #737373;
overflow: auto !important;
}
:deep(.module-footer) {
display: none !important;
}
</style>

View File

@@ -1,11 +1,11 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import type { DocConvertTask } from '@/service/api/tech-proposal';
import { useRouterPush } from '@/hooks/common/router';
import ImportantInfo from './modules/important-info copy.vue';
import TextContent from './modules/text-content copy.vue';
import ImageContent from './modules/image-content.vue';
import type { DocConvertTask } from '@/service/api/tech-proposal';
defineOptions({
name: 'ReviewProposal'
});
@@ -54,6 +54,7 @@ watch(
);
const { routerBack } = useRouterPush();
const currentTab = ref('ImportantInfo');
const textContentRef = ref<InstanceType<typeof TextContent>>();
const tabList = ref([
{
label: '重点信息',
@@ -81,20 +82,16 @@ const back = () => {
window.sessionStorage.setItem('review-proposal-tab', 'RegularAnalysis');
routerBack();
};
const saveTextContent = () => {
textContentRef.value?.handleConfirm?.();
};
</script>
<template>
<NFlex vertical :size="[0, 20]" class="contain h-full w-full bg-#F1F2F6">
<div class="contain-header flex items-center flex-justify-start bg-white">
<div class="flex items-center px-25px py-12px">
<NButton text>
<NIcon class="text-21px" @click="back">
<icon-local-back-icon class="block text-21px" />
</NIcon>
</NButton>
<NText class="ml-2 text-3.5 color-#333333">返回上一步</NText>
</div>
<div class="contain-header-tab ml-40px h-100% flex">
<NFlex vertical :size="[0, 0]" class="contain h-full w-full bg-#f6f8fc">
<div class="contain-header flex items-center justify-between bg-white">
<div class="contain-header-tab h-100% flex">
<div
v-for="item in tabList"
:key="item.value"
@@ -105,6 +102,12 @@ const back = () => {
<NText :class="item.value === currentTab ? 'text-#1e5ef9' : 'text-#333'">{{ item.label }}</NText>
</div>
</div>
<div class="contain-header-actions">
<button v-if="currentTab === 'TextContent'" class="save" type="button" @click="saveTextContent">
确定保存
</button>
<button class="cancel" type="button" @click="back">取消</button>
</div>
</div>
<div class="contain-main flex-1">
<div class="contain-main-wrapper h-100% w-100%">
@@ -121,6 +124,7 @@ const back = () => {
<FileAttrs v-else-if="currentTab === 'FileAttrs'" :parent-id="parentId" />
<TextContent
v-else-if="currentTab === 'TextContent'"
ref="textContentRef"
:parent-id="parentId"
:info-id="infoId"
:target-company="targetCompany"
@@ -148,20 +152,239 @@ const back = () => {
<style lang="scss" scoped>
.contain {
padding: 0;
overflow: hidden;
&-header {
box-shadow: 0rem 0.13rem 0.25rem rgba(122, 122, 122, 0.25);
height: 50px;
flex: 0 0 50px;
border-bottom: 1px solid #dfe6f2;
background: #fffaf4 !important;
box-shadow: none;
padding: 0 18px 0 40px;
&-tab {
.active-item {
background-color: rgba($color: #1e5ef9, $alpha: 0.1);
position: relative;
background-color: transparent;
font-weight: 700;
&::after {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 2px;
background: #1e5ef9;
content: '';
}
}
}
&-tab-item {
min-width: 64px;
justify-content: center;
padding: 0 18px !important;
font-size: 14px;
}
&-actions {
display: inline-flex;
align-items: center;
gap: 10px;
button {
min-width: 64px;
height: 32px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 700;
padding: 0 16px;
}
.save {
border: 1px solid #ff9f22;
background: linear-gradient(180deg, #ff9f22 0%, #ff8614 100%);
color: #fff;
}
.cancel {
border: 1px solid #ffd9a9;
background: #fff5e8;
color: #bd6a18;
}
}
}
&-main {
min-height: 0;
overflow-y: hidden;
padding: 14px 10px 16px;
background: #f6f8fc;
}
}
:deep(.module) {
height: 100% !important;
padding-bottom: 0 !important;
overflow: hidden !important;
}
:deep(.module-wrapper) {
box-sizing: border-box;
height: 100% !important;
gap: 14px !important;
padding: 0 14px !important;
}
:deep(.module-wrapper-sider) {
width: 230px !important;
flex: 0 0 230px !important;
border: 1px solid #dbe3ef;
border-radius: 4px !important;
background: #fff !important;
overflow: hidden;
}
:deep(.module-wrapper-sider-search) {
padding: 14px 14px 10px !important;
}
:deep(.module-wrapper-sider-search .n-input) {
--n-height: 32px !important;
--n-border-radius: 6px !important;
--n-border: 1px solid #dbe3ef !important;
--n-border-hover: 1px solid #b8c8e6 !important;
--n-border-focus: 1px solid #2d66ff !important;
--n-box-shadow-focus: none !important;
background: #fff !important;
box-shadow: none !important;
}
:deep(.module-wrapper-sider-header) {
height: 104px !important;
border-bottom: 1px solid #e8edf5;
border-radius: 0 !important;
background: #eef5ff !important;
background-image: none !important;
padding: 14px 10px !important;
}
:deep(.module-wrapper-sider-content) {
margin-top: 0 !important;
overflow: hidden !important;
}
:deep(.module-wrapper-sider-content .n-card) {
border-radius: 0 !important;
background: #fff !important;
}
:deep(.module-wrapper-sider-content .n-card-header) {
min-height: 42px;
border-bottom: 1px solid #e8edf5;
padding: 0 10px !important;
}
:deep(.module-wrapper-sider-content .n-card-header__main) {
color: #243044 !important;
font-size: 14px !important;
font-weight: 800 !important;
}
:deep(.module-wrapper-sider-content .n-card__content) {
padding: 0 !important;
}
:deep(.module-wrapper-sider-content .n-data-table-th) {
height: 36px;
background: #f7f8fb !important;
border-bottom: 1px solid #e8edf5 !important;
color: #0f1e36 !important;
font-weight: 800 !important;
}
:deep(.module-wrapper-sider-content .n-data-table-td) {
height: 34px;
border-bottom: 1px solid #edf1f6 !important;
color: #0f1e36 !important;
}
:deep(.module-wrapper-sider-content .selected-row),
:deep(.module-wrapper-sider-content .selected-row td) {
background: #eaf2ff !important;
color: #1f62ff !important;
}
:deep(.module-wrapper-content) {
min-width: 0;
flex: 1 1 0 !important;
width: auto !important;
border: 1px solid #dbe3ef;
border-radius: 0 !important;
background: #fff !important;
overflow: hidden;
}
:deep(.module-wrapper-content-card) {
border-radius: 0 !important;
}
:deep(.module-wrapper-content-card-header) {
height: 34px !important;
border-bottom: 1px solid #e8edf5 !important;
background: #fff !important;
padding-left: 76px !important;
}
:deep(.module-wrapper-content-card-header .n-text) {
color: #0f1e36 !important;
font-size: 14px !important;
font-weight: 800 !important;
}
:deep(.module-wrapper-content-card .gradient-1::before) {
width: auto !important;
height: 24px !important;
line-height: 24px !important;
top: 5px !important;
left: 10px !important;
border-radius: 4px !important;
background: linear-gradient(180deg, #5f90ff 0%, #3064df 100%) !important;
padding: 0 8px;
}
:deep(.module-wrapper-content-card .gradient-2::before) {
width: auto !important;
height: 24px !important;
line-height: 24px !important;
top: 5px !important;
left: 10px !important;
border-radius: 4px !important;
background: linear-gradient(180deg, #ffbe62 0%, #ff8d1f 100%) !important;
padding: 0 8px;
}
:deep(.module-wrapper-content-card-content) {
margin-top: 0 !important;
}
:deep(.module-wrapper-content-card-content-title) {
height: 34px;
border-bottom: 1px solid #eef2f7;
background: #fff !important;
padding: 0 10px !important;
color: #5e6777;
font-size: 12px;
}
:deep(.module-wrapper-content-card-content-body) {
border-radius: 0 !important;
background: #737373;
overflow: auto !important;
}
:deep(.module-footer) {
display: none !important;
}
</style>

View File

@@ -579,6 +579,10 @@ const handleConfirm = () => {
});
};
defineExpose({
handleConfirm
});
/** 清空数据 */
const clearData = () => {
htmlParams.value = {

View File

@@ -1,8 +1,8 @@
<script setup lang="tsx">
import { computed, ref } from 'vue';
import { NButton, NDivider } from 'naive-ui';
import { useLoading } from '@sa/hooks';
import { fetchBatchDeletePost, fetchGetPostDeptSelect, fetchGetPostList } from '@/service/api/system/post';
import { ref } from 'vue';
import { NDivider } from 'naive-ui';
import { fetchGetDeptSelect } from '@/service/api/system/dept';
import { fetchBatchDeletePost, fetchGetPostList } from '@/service/api/system/post';
import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useDownload } from '@/hooks/business/download';
@@ -11,6 +11,7 @@ import { useDict } from '@/hooks/business/dict';
import DictTag from '@/components/custom/dict-tag.vue';
import { $t } from '@/locales';
import ButtonIcon from '@/components/custom/button-icon.vue';
import { handleTree } from '@/utils/common';
import PostOperateDrawer from './modules/post-operate-drawer.vue';
import PostSearch from './modules/post-search.vue';
@@ -42,8 +43,7 @@ const {
// the value can not be undefined, otherwise the property in Form will not be reactive
postCode: null,
postName: null,
status: null,
belongDeptId: null
status: null
},
columns: () => [
{
@@ -180,163 +180,81 @@ async function handleExport() {
download('/system/post/export', searchParams, `岗位信息_${new Date().getTime()}.xlsx`);
}
const expandedKeys = ref<CommonType.IdType[]>([100]);
const selectable = computed(() => {
return !loading.value;
});
const { loading: treeLoading, startLoading: startTreeLoading, endLoading: endTreeLoading } = useLoading();
const deptPattern = ref<string>();
const deptData = ref<Api.Common.CommonTreeRecord>([]);
const selectedKeys = ref<string[]>([]);
function toCommonDeptTree(list: Record<string, any>[]) {
const tree = handleTree(
list.map(item => ({ ...item })),
{ idField: 'deptId' }
);
const normalize = (items: Record<string, any>[]): Record<string, any>[] =>
items.map(item => ({
...item,
id: item.deptId,
parentId: item.parentId,
label: item.deptName,
weight: item.orderNum ?? 0,
children: item.children?.length ? normalize(item.children) : []
}));
return normalize(tree) as Api.Common.CommonTreeRecord;
}
async function getDeptOptions() {
// 加载
startTreeLoading();
const { data: tree, error } = await fetchGetPostDeptSelect();
const { data: tree, error } = await fetchGetDeptSelect();
if (!error) {
deptData.value = tree;
deptData.value = toCommonDeptTree(tree || []);
}
endTreeLoading();
}
getDeptOptions();
function handleClickTree(keys: string[]) {
searchParams.belongDeptId = keys.length ? keys[0] : null;
checkedRowKeys.value = [];
getDataByPage();
}
function handleResetTreeData() {
deptPattern.value = undefined;
getDeptOptions();
}
function handleResetSearch() {
resetSearchParams();
selectedKeys.value = [];
}
</script>
<template>
<TableSiderLayout sider-title="部门列表">
<template #header-extra>
<NButton size="small" text class="h-18px" @click.stop="() => handleResetTreeData()">
<template #icon>
<SvgIcon icon="ic:round-refresh" />
</template>
</NButton>
</template>
<template #sider>
<NInput v-model:value="deptPattern" clearable :placeholder="$t('common.keywordSearch')" />
<NSpin class="dept-tree" :show="treeLoading">
<NTree
v-model:expanded-keys="expandedKeys"
v-model:selected-keys="selectedKeys"
block-node
show-line
:data="deptData as []"
:show-irrelevant-nodes="false"
:pattern="deptPattern"
block-line
class="infinite-scroll h-full min-h-200px py-3"
key-field="id"
label-field="label"
virtual-scroll
:selectable="selectable"
@update:selected-keys="handleClickTree"
>
<template #empty>
<NEmpty description="暂无部门信息" class="h-full min-h-200px justify-center" />
</template>
</NTree>
</NSpin>
</template>
<div class="h-full flex-col-stretch gap-12px overflow-hidden lt-sm:overflow-auto">
<PostSearch v-model:model="searchParams" @reset="handleResetSearch" @search="getDataByPage" />
<NCard title="岗位信息列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
<template #header-extra>
<TableHeaderOperation
v-model:columns="columnChecks"
:disabled-delete="checkedRowKeys.length === 0"
:loading="loading"
:show-add="hasAuth('system:post:add')"
:show-delete="hasAuth('system:post:remove')"
:show-export="hasAuth('system:post:export')"
@add="handleAdd"
@delete="handleBatchDelete"
@export="handleExport"
@refresh="getData"
/>
</template>
<NDataTable
v-model:checked-row-keys="checkedRowKeys"
:columns="columns"
:data="data"
size="small"
:flex-height="!appStore.isMobile"
:scroll-x="962"
<div class="h-full flex-col-stretch gap-12px overflow-hidden lt-sm:overflow-auto">
<PostSearch v-model:model="searchParams" @reset="handleResetSearch" @search="getDataByPage" />
<NCard title="岗位信息列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
<template #header-extra>
<TableHeaderOperation
v-model:columns="columnChecks"
:disabled-delete="checkedRowKeys.length === 0"
:loading="loading"
remote
:row-key="row => row.postId"
:pagination="mobilePagination"
class="sm:h-full"
:show-add="hasAuth('system:post:add')"
:show-delete="hasAuth('system:post:remove')"
:show-export="hasAuth('system:post:export')"
@add="handleAdd"
@delete="handleBatchDelete"
@export="handleExport"
@refresh="getData"
/>
<PostOperateDrawer
v-model:visible="drawerVisible"
:operate-type="operateType"
:row-data="editingData"
:dept-data="deptData"
@submitted="getData"
/>
</NCard>
</div>
</TableSiderLayout>
</template>
<NDataTable
v-model:checked-row-keys="checkedRowKeys"
:columns="columns"
:data="data"
size="small"
:flex-height="!appStore.isMobile"
:scroll-x="962"
:loading="loading"
remote
:row-key="row => row.postId"
:pagination="mobilePagination"
class="sm:h-full"
/>
<PostOperateDrawer
v-model:visible="drawerVisible"
:operate-type="operateType"
:row-data="editingData"
:dept-data="deptData"
@submitted="getData"
/>
</NCard>
</div>
</template>
<style scoped lang="scss">
.dept-tree {
.n-button {
--n-padding: 8px !important;
}
:deep(.n-tree__empty) {
height: 100%;
justify-content: center;
}
:deep(.n-spin-content) {
height: 100%;
}
:deep(.infinite-scroll) {
height: calc(100vh - 228px - var(--calc-footer-height, 0px)) !important;
max-height: calc(100vh - 228px - var(--calc-footer-height, 0px)) !important;
}
@media screen and (max-width: 1024px) {
:deep(.infinite-scroll) {
height: calc(100vh - 227px - var(--calc-footer-height, 0px)) !important;
max-height: calc(100vh - 227px - var(--calc-footer-height, 0px)) !important;
}
}
:deep(.n-tree-node) {
height: 30px;
}
:deep(.n-tree-node-switcher) {
height: 30px;
}
:deep(.n-tree-node-switcher__icon) {
font-size: 16px !important;
height: 16px !important;
width: 16px !important;
}
}
:deep(.n-data-table-wrapper),
:deep(.n-data-table-base-table),
:deep(.n-data-table-base-table-body) {

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Client' });
</script>
<template>
<System2ListPage page-key="client" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Config' });
</script>
<template>
<System2ListPage page-key="config" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Dept' });
</script>
<template>
<System2ListPage page-key="dept" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Dict' });
</script>
<template>
<System2ListPage page-key="dict" />
</template>

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({
name: 'System2Log'
});
</script>
<template>
<System2ListPage page-key="log" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Menu' });
</script>
<template>
<System2ListPage page-key="menu" />
</template>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Notice' });
</script>
<template>
<System2ListPage page-key="notice" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Oss' });
</script>
<template>
<System2ListPage page-key="oss" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Post' });
</script>
<template>
<System2ListPage page-key="post" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2Role' });
</script>
<template>
<System2ListPage page-key="role" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import System2ListPage from '../modules/system2-list-page.vue';
defineOptions({ name: 'System2User' });
</script>
<template>
<System2ListPage page-key="user" />
</template>