From dca4521b3584ec810b73822a7b2f5d6aeec025d9 Mon Sep 17 00:00:00 2001 From: cjh <949661474@qq.com> Date: Thu, 4 Jun 2026 11:12:09 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A1=B5=E9=9D=A2=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/router.ts | 31 +- src/locales/langs/en-us.ts | 12 + src/locales/langs/zh-cn.ts | 12 + src/router/elegant/imports.ts | 11 + src/router/elegant/routes.ts | 115 + src/router/elegant/transform.ts | 12 + src/router/routes/index.ts | 79 + src/service/api/system/dept.ts | 5 +- src/typings/elegant-router.d.ts | 24 + src/views/ai-assistant/ai-read/index.vue | 26 +- .../content-check/index.vue | 2 - .../tech-proposal-redesign/index.vue | 1861 +++++++++-- .../regular-analysis/index.vue | 253 +- .../responsive-check/index.vue | 51 +- .../modules/analysis-info/index.vue | 235 +- .../modules/rewrite-info/index.vue | 251 +- .../modules/text-content copy.vue | 4 + src/views/system/post/index.vue | 206 +- src/views/system2/client/index.vue | 9 + src/views/system2/config/index.vue | 9 + src/views/system2/dept/index.vue | 9 + src/views/system2/dict/index.vue | 9 + src/views/system2/log/index.vue | 11 + src/views/system2/menu/index.vue | 9 + .../system2/modules/system2-list-page.vue | 2811 +++++++++++++++++ src/views/system2/notice/index.vue | 9 + src/views/system2/oss/index.vue | 9 + src/views/system2/post/index.vue | 9 + src/views/system2/role/index.vue | 9 + src/views/system2/user/index.vue | 9 + 30 files changed, 5562 insertions(+), 540 deletions(-) create mode 100644 src/views/system2/client/index.vue create mode 100644 src/views/system2/config/index.vue create mode 100644 src/views/system2/dept/index.vue create mode 100644 src/views/system2/dict/index.vue create mode 100644 src/views/system2/log/index.vue create mode 100644 src/views/system2/menu/index.vue create mode 100644 src/views/system2/modules/system2-list-page.vue create mode 100644 src/views/system2/notice/index.vue create mode 100644 src/views/system2/oss/index.vue create mode 100644 src/views/system2/post/index.vue create mode 100644 src/views/system2/role/index.vue create mode 100644 src/views/system2/user/index.vue diff --git a/src/hooks/common/router.ts b/src/hooks/common/router.ts index 280d8dd..b3936e3 100644 --- a/src/hooks/common/router.ts +++ b/src/hooks/common/router.ts @@ -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 = {}; @@ -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() { diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts index f9ace11..a6f5a1b 100644 --- a/src/locales/langs/en-us.ts +++ b/src/locales/langs/en-us.ts @@ -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', diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts index feee736..f6fdc55 100644 --- a/src/locales/langs/zh-cn.ts +++ b/src/locales/langs/zh-cn.ts @@ -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: '代码生成', diff --git a/src/router/elegant/imports.ts b/src/router/elegant/imports.ts index 8fbb6f6..08b1128 100644 --- a/src/router/elegant/imports.ts +++ b/src/router/elegant/imports.ts @@ -74,5 +74,16 @@ export const views: Record Promise 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"), }; diff --git a/src/router/elegant/routes.ts b/src/router/elegant/routes.ts index daefdd2..e1c242b 100644 --- a/src/router/elegant/routes.ts +++ b/src/router/elegant/routes.ts @@ -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', diff --git a/src/router/elegant/transform.ts b/src/router/elegant/transform.ts index 02492e3..645828e 100644 --- a/src/router/elegant/transform.ts +++ b/src/router/elegant/transform.ts @@ -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" diff --git a/src/router/routes/index.ts b/src/router/routes/index.ts index 9292af7..c405e16 100644 --- a/src/router/routes/index.ts +++ b/src/router/routes/index.ts @@ -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 } + } + ] } ]; diff --git a/src/service/api/system/dept.ts b/src/service/api/system/dept.ts index a678e56..2f61b7d 100644 --- a/src/service/api/system/dept.ts +++ b/src/service/api/system/dept.ts @@ -43,9 +43,10 @@ export function fetchBatchDeleteDept(deptIds: CommonType.IdType[]) { } /** 获取部门选择框列表 */ -export function fetchGetDeptSelect() { +export function fetchGetDeptSelect(deptIds?: CommonType.IdType[]) { return request({ url: '/system/dept/optionselect', - method: 'get' + method: 'get', + params: { deptIds } }); } diff --git a/src/typings/elegant-router.d.ts b/src/typings/elegant-router.d.ts index 95239ce..748577a 100644 --- a/src/typings/elegant-router.d.ts +++ b/src/typings/elegant-router.d.ts @@ -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" >; diff --git a/src/views/ai-assistant/ai-read/index.vue b/src/views/ai-assistant/ai-read/index.vue index ef4de3a..bc8e71a 100644 --- a/src/views/ai-assistant/ai-read/index.vue +++ b/src/views/ai-assistant/ai-read/index.vue @@ -169,8 +169,8 @@ watch(fileList, value => {
@@ -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 { diff --git a/src/views/ai-review/tech-proposal-redesign/content-check/index.vue b/src/views/ai-review/tech-proposal-redesign/content-check/index.vue index 003e5af..3d8e4e5 100644 --- a/src/views/ai-review/tech-proposal-redesign/content-check/index.vue +++ b/src/views/ai-review/tech-proposal-redesign/content-check/index.vue @@ -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 diff --git a/src/views/ai-review/tech-proposal-redesign/index.vue b/src/views/ai-review/tech-proposal-redesign/index.vue index 4d006bb..f835262 100644 --- a/src/views/ai-review/tech-proposal-redesign/index.vue +++ b/src/views/ai-review/tech-proposal-redesign/index.vue @@ -56,7 +56,6 @@ import { useAIReviewStore } from '@/store/modules/ai-review/index'; import { useAppStore } from '@/store/modules/app'; import { useDownload } from '@/hooks/business/download'; import { randomIntId } from '@/utils/common'; -import { useTaskStorage } from '@/utils/strorage-manager'; import defaultSetting from '@/assets/json/defaultSetting.json'; import ButtonIcon from '@/components/custom/button-icon.vue'; import FileUploadButton from '@/components/custom/file-upload-button.vue'; @@ -64,6 +63,10 @@ import FileUploadFolder from '@/components/custom/file-upload-folder.vue'; import DocPreview from '@/components/custom/doc-preview.vue'; import HtmlFilePreview from '@/components/html-file/index-only-read.vue'; import SettingDrawer from '../tech-proposal/modules/review-proposal/content-check/modules/setting-drawer.vue'; +import AnalysisFileAttrs from '../tech-proposal/modules/rewrite-info/modules/file-attrs.vue'; +import AnalysisImageContent from '../tech-proposal/modules/rewrite-info/modules/image-content.vue'; +import AnalysisImportantInfo from '../tech-proposal/modules/rewrite-info/modules/important-info copy.vue'; +import AnalysisTextContent from '../tech-proposal/modules/rewrite-info/modules/text-content copy.vue'; import UploadLoading from '../tech-proposal/modules/upload-proposal/step-two/modules/upload-loading.vue'; import Reupload from './reupload/index.vue'; import ContentCheck from './content-check/index.vue'; @@ -231,6 +234,10 @@ const analysisReferenceData = ref([]); const analysisResultLoading = ref(false); const analysisCheckedRowKeys = ref>([]); const analysisSmartFilterVisible = ref(false); +const analysisCompareVisible = ref(false); +const analysisCompareTab = ref<'key' | 'attr' | 'text' | 'image'>('key'); +const analysisCompareRow = ref(null); +const analysisTextContentRef = ref>(); const analysisRuleJsonSetting = ref({ checkFileProperties: true, checkDuplicateContent: 100, @@ -259,14 +266,32 @@ const analysisScopeOptions = [ { value: true, label: '段落' }, { value: false, label: '语句' } ] as any[]; +const analysisCompareTabs = [ + { key: 'key', label: '重点信息' }, + { key: 'attr', label: '文件属性' }, + { key: 'text', label: '文本' }, + { key: 'image', label: '图片' } +] as const; const analysisInfoOptions = ['地名', '人名', '身份证号', '项目名'].map(value => ({ value, label: value })); +const analysisCompareParentId = computed(() => Number(analysisCompareRow.value?.id || 0)); +const analysisCompareTargetCompany = computed(() => analysisCompareRow.value?.proposal1Name || '投标单位A'); +const analysisCompareCurrentCompany = computed(() => analysisCompareRow.value?.proposal2Name || '投标单位B'); +const analysisCompareProposalId1 = computed(() => String(analysisCompareRow.value?.proposalId1 || '')); +const analysisCompareProposalId2 = computed(() => String(analysisCompareRow.value?.proposalId2 || '')); +const analysisCompareInfoId = computed(() => String(resultInfoId.value || '')); +const analysisSmartFilterKeyInfoType = computed({ + get: () => analysisSmartFilterSetting.value.ignoreKeyInfoTypes?.[0] || '地名', + set: value => { + analysisSmartFilterSetting.value.ignoreKeyInfoTypes = value ? [value] : []; + } +}); let resultTimer: number | null = null; let responseRuleTimer: number | null = null; let responseResultTimer: number | null = null; let analysisResultTimer: number | null = null; let reviewRequestId = 0; -const { findTaskByBId, addTask, removeTaskByBId } = useTaskStorage('repCheckId'); +let responseRuleTaskId: string | number | null = null; const activeRuleList = computed(() => templateOptions.value); const checkRuleRows = computed(() => ruleDataList.value.map((item, index) => ({ ...item, index: index + 1 }))); @@ -308,14 +333,15 @@ const contentReviewStatus = computed(() => getReviewStatusFromRows(reviewResultC const regularAnalysisReviewStatus = computed(() => getReviewStatusFromRows(analysisResultData.value)); const responseRuleTableRows = computed(() => { const rows: any[] = []; - responseRuleList.value.forEach((group, index) => { - const expanded = responseExpandedIds.value.includes(group.id); - rows.push({ ...group, index: index + 1, depth: 0, expanded, isGroup: true }); - if (!expanded) return; - (group.subItems || []).forEach((child: any) => { - rows.push({ ...child, index: '', depth: 1, parentId: group.id, isGroup: false }); + const walk = (nodes: any[] = [], depth = 0) => { + nodes.forEach((node, index) => { + const expanded = responseExpandedIds.value.includes(node.id); + const isGroup = Array.isArray(node.subItems); + rows.push({ ...node, index: depth === 0 ? index + 1 : '', depth, expanded, isGroup }); + if (expanded && node.subItems?.length) walk(node.subItems, depth + 1); }); - }); + }; + walk(responseRuleList.value); return rows; }); const selectedResponseDocName = computed(() => { @@ -375,8 +401,6 @@ const activeReviewStatus = computed(() => { if (reviewInnerTab.value === 'RegularAnalysis') return regularAnalysisReviewStatus.value; return ''; }); -const detailPageCount = computed(() => Math.ceil(detailTotal.value / detailPagination.value.pageSize)); -const historyPageCount = computed(() => Math.ceil(historyTotal.value / historyPagination.value.pageSize)); const detailTreeRows = computed(() => { const rows: any[] = []; const walk = (nodes: any[] = [], depth = 0, parent: any = null) => { @@ -575,6 +599,41 @@ const updateResponseCheckedKeys = (keys: Array) => { responseCheckedKeys.value = keys; }; +function getResponseRuleIds(nodes: any[] = []) { + const ids: Array = []; + nodes.forEach(node => { + ids.push(node.id); + if (node.subItems?.length) ids.push(...getResponseRuleIds(node.subItems)); + }); + return ids; +} + +function getResponseNodeDescendantIds(id: string | number, nodes: any[] = []): Array { + const collect = (node: any): Array => { + const ids: Array = []; + node.subItems?.forEach((child: any) => { + ids.push(child.id, ...collect(child)); + }); + return ids; + }; + for (const node of nodes) { + if (node.id === id) return collect(node); + const found = getResponseNodeDescendantIds(id, node.subItems || []); + if (found.length) return found; + } + return []; +} + +const toggleResponseCheckedKey = (key: string | number, checked: boolean) => { + const checkedSet = new Set(responseCheckedKeys.value); + const relatedKeys = [key, ...getResponseNodeDescendantIds(key, responseRuleList.value)]; + relatedKeys.forEach(item => { + if (checked) checkedSet.add(item); + else checkedSet.delete(item); + }); + responseCheckedKeys.value = Array.from(checkedSet); +}; + const queryResponseRule = async () => { if (!resultInfoId.value) return; const { data } = await queryResponseCheckRule({ infoId: resultInfoId.value }); @@ -582,20 +641,10 @@ const queryResponseRule = async () => { if (rows.length > 0) { responseRuleId.value = rows[0].id || 0; statusResult.value = rows[0].status || statusResult.value; - let parsedRuleList: any[] = []; - try { - parsedRuleList = JSON.parse(rows[0].content || '[]'); - } catch { - parsedRuleList = []; - } - if (Array.isArray(parsedRuleList) && parsedRuleList.length) responseRuleList.value = parsedRuleList; - selectedResponseRuleId.value ||= responseRuleList.value[0]?.id || null; - responseExpandedIds.value = responseRuleList.value.map(item => item.id); - } else { - responseRuleId.value = 0; - responseRuleList.value = []; - selectedResponseRuleId.value = null; - responseExpandedIds.value = []; + responseRuleList.value = JSON.parse(rows[0].content || '[]'); + selectedResponseRuleId.value = responseRuleList.value[0]?.id || null; + responseExpandedIds.value = getResponseRuleIds(responseRuleList.value); + responseCheckedKeys.value = []; } }; @@ -616,7 +665,7 @@ const toggleResponseRuleExpand = (id: string | number) => { }; const expandAllResponseRules = () => { - responseExpandedIds.value = responseRuleList.value.map(item => item.id); + responseExpandedIds.value = getResponseRuleIds(responseRuleList.value); }; const collapseAllResponseRules = () => { @@ -660,6 +709,7 @@ const saveResponseRuleData = async (showConfirm = true) => { const savedId = typeof savedData === 'object' ? savedData?.id : savedData; if (!responseRuleId.value && savedId) responseRuleId.value = Number(savedId); window.$message?.success('操作成功'); + await queryResponseRule(); } }; @@ -669,7 +719,7 @@ const saveResponseRuleData = async (showConfirm = true) => { } window.$dialog?.warning({ title: '提示', - content: '是否要保存当前响应式规则?', + content: '是否要保存当前模块?', positiveText: '确认', negativeText: '取消', onPositiveClick: doSave @@ -689,7 +739,6 @@ const addResponseModule = (type: string, id?: string | number) => { if (type === 'root') { responseRuleList.value.push(node); selectedResponseRuleId.value = nodeId; - responseExpandedIds.value = [...responseExpandedIds.value, nodeId]; return; } const findAndAdd = (nodes: any[]): boolean => { @@ -698,7 +747,6 @@ const addResponseModule = (type: string, id?: string | number) => { item.subItems ||= []; item.subItems.push({ ...node, subItems: undefined }); selectedResponseRuleId.value = nodeId; - responseExpandedIds.value = Array.from(new Set([...responseExpandedIds.value, item.id])); return true; } if (item.subItems?.length && findAndAdd(item.subItems)) return true; @@ -759,10 +807,6 @@ const openResponseModuleDialog = (handleType: 'add' | 'edit', type: 'root' | 'le { type: 'info', onClick: () => { - if (!responseAddModuleForm.value.name.trim()) { - window.$message?.warning('请输入评分项名称'); - return; - } if (handleType === 'add') addResponseModule(type, row?.id); else updateResponseModule(row?.id); responseAddModuleForm.value = { name: '', scoringStandard: '' }; @@ -774,7 +818,7 @@ const openResponseModuleDialog = (handleType: 'add' | 'edit', type: 'root' | 'le }); }; -function deleteResponseModule(id: string | number) { +function removeResponseModule(id: string | number) { const findAndDel = (nodes: any[]): boolean => { for (let i = 0; i < nodes.length; i += 1) { const item = nodes[i]; @@ -787,7 +831,18 @@ function deleteResponseModule(id: string | number) { return false; }; findAndDel(responseRuleList.value); - if (selectedResponseRuleId.value === id) selectedResponseRuleId.value = responseRuleList.value[0]?.id || null; + selectedResponseRuleId.value = responseRuleList.value[0]?.id || null; + responseCheckedKeys.value = []; +} + +function deleteResponseModule(id: string | number) { + window.$dialog?.warning({ + title: '提示', + content: '确认删除吗?', + positiveText: '确认', + negativeText: '取消', + onPositiveClick: () => removeResponseModule(id) + }); } const batchDeleteResponseModule = () => { @@ -817,18 +872,17 @@ const batchDeleteResponseModule = () => { }; const queryResponseRuleByTaskId = async () => { - const hasTaskId = findTaskByBId(resultInfoId.value); - if (!hasTaskId) { + if (!responseRuleTaskId) { responseGenerateLoading.value = false; window.$message?.warning('请确认是否使用了AI智能识别生成检查规则!'); return; } - const { response } = await queryResponseCheckResultByTaskId(hasTaskId.id); + const { response } = await queryResponseCheckResultByTaskId(responseRuleTaskId); responseGenerateLoading.value = false; const code = response.data.code as any; if (code === 500) { window.$message?.warning('未识别到评审模块或招标文件格式不正确,请检查!'); - removeTaskByBId(resultInfoId.value); + responseRuleTaskId = null; if (responseRuleTimer) { window.clearInterval(responseRuleTimer); responseRuleTimer = null; @@ -838,12 +892,12 @@ const queryResponseRuleByTaskId = async () => { if (response.data.data) { responseRuleList.value = response.data.data as any[]; selectedResponseRuleId.value = responseRuleList.value[0]?.id || null; - removeTaskByBId(resultInfoId.value); + responseRuleTaskId = null; if (responseRuleTimer) { window.clearInterval(responseRuleTimer); responseRuleTimer = null; } - await saveResponseRuleData(false); + await saveResponseRuleData(); } else { window.$message?.info('暂未生成评审模块'); } @@ -861,26 +915,29 @@ const generateResponseRule = async () => { negativeText: '取消', onPositiveClick: async () => { window.$dialog?.destroyAll(); - const hasTaskId = findTaskByBId(resultInfoId.value); responseGenerateLoading.value = true; - if (hasTaskId) { + if (responseRuleTaskId) { if (!responseRuleTimer) responseRuleTimer = window.setInterval(queryResponseRuleByTaskId, 5000); return; } window.$message?.success('正在使用AI智能识别规则'); const { response } = await generateResponseCheckRule(responseAiBidding.value); - addTask({ bId: resultInfoId.value, id: response.data.msg }); + responseRuleTaskId = response.data.msg; if (!responseRuleTimer) responseRuleTimer = window.setInterval(queryResponseRuleByTaskId, 5000); } }); }; const handleResponseHistoryRuleChange = (value: any) => { - if (!value) return; + if (!value) { + responseCheckedKeys.value = []; + return; + } const obj = responseHistoryBiddingOptions.value.find((item: any) => item.id === value); - if (obj?.ruleContent) responseRuleList.value = JSON.parse(obj.ruleContent); + if (obj?.ruleContent) responseRuleList.value = parseResponseJson(obj.ruleContent, []); selectedResponseRuleId.value = responseRuleList.value[0]?.id || null; - responseExpandedIds.value = responseRuleList.value.map(item => item.id); + responseExpandedIds.value = getResponseRuleIds(responseRuleList.value); + responseCheckedKeys.value = []; }; const getResponseStatisticData = (list: any[]) => { @@ -896,14 +953,14 @@ const getResponseStatisticData = (list: any[]) => { responseStatisticData.value.abnormalCompanyNum = abnormalCompanyNum; }; -const parseResponseJson = (value: any, fallback: any = []) => { +function parseResponseJson(value: any, fallback: any = []) { if (typeof value !== 'string') return value ?? fallback; try { return JSON.parse(value); } catch { return fallback; } -}; +} const normalizeResponseResultPayload = (rawData: any) => { const payload = rawData || {}; @@ -988,7 +1045,8 @@ async function queryResponseResult() { if (!responseRuleList.value.length && ruleJson.length) { responseRuleList.value = JSON.parse(JSON.stringify(ruleJson)); selectedResponseRuleId.value = responseRuleList.value[0]?.id || null; - responseExpandedIds.value = responseRuleList.value.map(item => item.id); + responseExpandedIds.value = getResponseRuleIds(responseRuleList.value); + responseCheckedKeys.value = []; } const allCompleted = result.every((item: any) => item.taskStatus === '审查完成'); if (allCompleted && responseResultTimer) { @@ -1064,10 +1122,18 @@ const submitResponseDocModal = async () => { window.$message?.warning('请先上传招标文件'); return; } - await batchAddBiddingDoc(params); - window.$message?.success('添加成功'); - cancelResponseDocModal(); - await handleGetBiddingDocListAll(); + window.$dialog?.warning({ + title: '提示', + content: '是否确认添加文件?', + positiveText: '确认', + negativeText: '取消', + onPositiveClick: async () => { + await batchAddBiddingDoc(params); + window.$message?.success('添加成功'); + cancelResponseDocModal(); + await handleGetBiddingDocListAll(); + } + }); }; const handleEditRule = (row?: any) => { @@ -1443,6 +1509,12 @@ const closeContentDetailPanel = () => { detailPagination.value.page = 1; }; +const closeAnalysisCompareModal = () => { + analysisCompareVisible.value = false; + analysisCompareRow.value = null; + analysisCompareTab.value = 'key'; +}; + const getDetailDocPresign = (docId: string) => detailDocPresignCache.get(docId) || null; const setDetailDocPresign = (docId: string, data: DocConvertTask) => { @@ -1474,20 +1546,24 @@ function getAnalysisValue(row: any, keys: string[], defaultValue: any = '-') { return value ?? defaultValue; } +const changeAnalysisCompareTab = (tab: 'key' | 'attr' | 'text' | 'image') => { + analysisCompareTab.value = tab; +}; + const analysisResultColumns: any[] = [ - { type: 'selection', width: 48 }, - { title: '序号', key: 'index', width: 70, render: (_row: any, index: number) => index + 1 }, + { type: 'selection', width: 38 }, + { title: '序号', key: 'index', width: 46, render: (_row: any, index: number) => index + 1 }, { title: '目标单位', key: 'proposal2Name', - width: 180, + minWidth: 92, ellipsis: { tooltip: true }, render: (row: any) => getAnalysisValue(row, ['proposal2Name', 'targetCompany', 'targetName', 'companyName']) }, { title: '风险度', key: 'riskDegree', - width: 82, + width: 62, render: (row: any) => { const value = getAnalysisValue(row, ['riskDegree', 'riskDgree', 'rewriteRiskDegree'], 0); return 60 ? 'analysis-risk high' : 'analysis-risk'}>{value}; @@ -1496,31 +1572,31 @@ const analysisResultColumns: any[] = [ { title: '文本相似度(%)', key: 'textSimilarity', - width: 120, + width: 92, render: (row: any) => getAnalysisValue(row, ['textSimilarity', 'rewriteTextSimilarity'], 0) }, { title: '图片相似度(%)', key: 'imgSimilarity', - width: 120, + width: 92, render: (row: any) => getAnalysisValue(row, ['imgSimilarity', 'imageSimilarity'], 0) }, { title: '文件属性雷同', key: 'docSimilarity', - width: 120, + width: 96, render: (row: any) => getAnalysisValue(row, ['docSimilarity', 'fileSimilarity'], 0) }, { title: '重点信息雷同(项)', key: 'informationSimilarity', - width: 142, + width: 118, render: (row: any) => getAnalysisValue(row, ['informationSimilarity', 'keyInformationSimilarity'], 0) }, { title: '检查状态', key: 'taskStatus', - width: 112, + width: 92, render: (row: any) => { const status = row.taskStatus || '未审查'; return ( @@ -1533,7 +1609,7 @@ const analysisResultColumns: any[] = [ { title: '操作', key: 'operate', - width: 130, + width: 98, render: (row: any) => (
openAnalysisInfo(row, true)}> @@ -1683,6 +1759,36 @@ const startRegularAnalysis = async () => { }); }; +const reAnalysisRegularAnalysis = async () => { + const proposalDtlIds1 = analysisResultData.value.map((item: any) => item.proposalDtlId1).filter(Boolean); + const proposalDtlIds2 = analysisResultData.value.map((item: any) => item.proposalDtlId2).filter(Boolean); + if (!proposalDtlIds1.length || !proposalDtlIds2.length) { + window.$message?.warning('暂无可重新分析的投标文件'); + return; + } + window.$dialog?.warning({ + title: '提示', + content: '是否重新分析投标文件?', + positiveText: '确认', + negativeText: '取消', + onPositiveClick: async () => { + window.$dialog?.destroyAll(); + btnLoading.value = true; + const { error } = await startAnalysis({ + infoId: resultInfoId.value, + proposalDtlIds1, + proposalDtlIds2, + ruleJson: '', + smartFilterConfig: '' + }); + btnLoading.value = false; + if (!error) window.$message?.success('开始规律性分析!请等待生成检查结果'); + await loadAnalysisResult(); + if (!analysisResultTimer) analysisResultTimer = window.setInterval(loadAnalysisResult, 5000); + } + }); +}; + const rewriteRegularAnalysis = () => { if (!analysisCheckedRowKeys.value.length) { window.$message?.warning('请勾选需要一键改写的投标单位'); @@ -1745,26 +1851,21 @@ async function deleteAnalysisFile(id: any) { }); } -async function openAnalysisInfo(row: any, editType: boolean) { +function openAnalysisInfo(row: any, _editType: boolean) { + currentStep.value = 3; + reviewInnerTab.value = 'RegularAnalysis'; + analysisCompareRow.value = row; + analysisCompareVisible.value = true; + changeAnalysisCompareTab('key'); + const taskId = row.taskId; if (taskId) { - const ok = await queryCheckResultStatus(taskId); - if (ok.data?.errorMsg) { - window.$message?.error(ok.data.errorMsg); - return; - } + queryCheckResultStatus(taskId) + .then(ok => { + if (ok.data?.errorMsg) window.$message?.error(ok.data.errorMsg); + }) + .catch(() => undefined); } - router.push({ - name: editType ? 'ai-review_tech-proposal_modules_rewrite-info' : 'ai-review_tech-proposal_modules_analysis-info', - query: { - id: row.id?.toString(), - targetCompany: row.proposal1Name, - currentCompany: row.proposal2Name, - infoId: resultInfoId.value.toString(), - proposalId1: row.proposalId1, - proposalId2: row.proposalId2 - } - }); } const inviteFileSizeMB = computed(() => { @@ -1860,6 +1961,7 @@ watch( watch(reviewInnerTab, (value, oldValue) => { if (oldValue === 'ContentCheck' && value !== 'ContentCheck') closeContentDetailPanel(); + if (oldValue === 'RegularAnalysis' && value !== 'RegularAnalysis') closeAnalysisCompareModal(); if (oldValue === 'Reupload' && value !== 'Reupload') loadReuploadData(); if (value === 'Reupload') loadReuploadData(); if (value === 'ResponsiveCheck') loadResponsiveCheckData(); @@ -2396,7 +2498,6 @@ const columns: any = [ const topIndex = Number(String(row.index).split('-')[0]) - 1; const editBtn = () => ( ( { const backToUpload = () => { reviewRequestId += 1; + closeAnalysisCompareModal(); resetUploadDraft(); currentStep.value = 1; reviewInnerTab.value = 'ContentCheck'; @@ -2660,6 +2760,7 @@ provide(techProposalRedesignContextKey, { collapseAllResponseRules, columns, dataList, + deleteAnalysisFile, deleteAllBiddingDoc, deleteResponseModule, detailActiveTreeId, @@ -2668,7 +2769,6 @@ provide(techProposalRedesignContextKey, { detailFixedCount, detailIssueCount, detailLoading, - detailPageCount, detailPagination, detailRowProps, detailSelectedRowId, @@ -2695,6 +2795,7 @@ provide(techProposalRedesignContextKey, { handleUploadBefore, handleUploadError, loadDetailTree, + openAnalysisInfo, openAnalysisSmartFilter, openResponseModuleDialog, openResultDetail, @@ -2705,6 +2806,7 @@ provide(techProposalRedesignContextKey, { proposalFolderList, queryDetailByPage, queryResponseResult, + reAnalysisRegularAnalysis, responseAddDocForm, responseAddDocVisible, responseAiBidding, @@ -2720,6 +2822,7 @@ provide(techProposalRedesignContextKey, { responseResultScrollX, responseResultTableRows, responseReviewStatus, + responseCheckedKeys, responseRuleTableRows, responseSourceTab, responseStartCheck, @@ -2746,6 +2849,7 @@ provide(techProposalRedesignContextKey, { systemRuleOptions, tableRowProps, toggleExpandAll, + toggleResponseCheckedKey, toggleResponseRuleExpand, toggleSelectedRuleLock, updateResponseCheckedKeys, @@ -2766,10 +2870,12 @@ onActivated(() => { onDeactivated(() => { closeContentDetailPanel(); + closeAnalysisCompareModal(); }); onUnmounted(() => { closeContentDetailPanel(); + closeAnalysisCompareModal(); if (resultTimer) { window.clearInterval(resultTimer); resultTimer = null; @@ -3021,17 +3127,23 @@ onUnmounted(() => { 搜索
-
+
- {{ item.sectionName }} - + {{ item.sectionName }} + + +

清标编号:{{ item.clearingNumber || '-' }}

投标单位:{{ item.proposalCount || 0 }} 家

@@ -3047,7 +3159,6 @@ onUnmounted(() => { v-model:page="historyPagination.page" v-model:page-size="historyPagination.pageSize" :item-count="historyTotal" - :page-count="historyPageCount" :page-sizes="[20, 50]" size="small" show-size-picker @@ -3111,67 +3222,122 @@ onUnmounted(() => {
-
-
- 忽略与招标文件相同内容 -

过滤投标文件中直接引用招标文件的段落。

-
- -
-
-
- 忽略目录 -

目录页和章节索引不参与相似度判断。

-
- -
-
-
- 忽略文件中的技术标准 -

过滤常见规范、标准条文等公共文本。

-
- -
-
-
- 忽略标点符号及短文本 -

小于指定字数的内容不进入重复度计算。

-
-
- - - 字以内 -
-
-
-
- 忽略以下类重点信息 -

适用于地名、人名等非关键雷同项。

-
-
- - -
-
+ + + + +
+
+
+
+
+ +
+
+ + +
+
+
+ + + + +
+
+
@@ -4824,23 +4990,34 @@ onUnmounted(() => { grid-template-rows: auto minmax(0, 1fr); overflow: hidden; border: 1px solid #dfe6f1; - border-radius: 12px; + border-radius: 8px; background: #fff; + box-shadow: none; } .regular-config-toolbar, .regular-result-toolbar { display: flex; - min-height: 48px; + min-height: 42px; align-items: center; justify-content: space-between; - border-bottom: 1px solid #e8edf5; - padding: 8px 12px 8px 14px; + gap: 10px; + flex-wrap: nowrap; + border-bottom: 1px solid #edf1f6; + background: #fff; + padding: 6px 10px 6px 14px; + + .result-title { + flex: 0 1 220px; + } +} + +.regular-result-toolbar { + flex-wrap: nowrap; } .regular-config-toolbar { position: relative; - justify-content: flex-start; padding-right: 14px; .review-start-check { @@ -4849,6 +5026,51 @@ onUnmounted(() => { align-items: center; justify-content: center; margin-left: auto; + min-width: 76px; + height: 30px; + border-radius: 8px !important; + box-shadow: none; + } +} + +.regular-panel-title { + display: flex; + min-width: 0; + align-items: center; + gap: 10px; + + strong { + display: block; + color: #152033; + font-size: 14px; + font-weight: 900; + line-height: 18px; + } + + p { + margin: 2px 0 0; + overflow: hidden; + color: #718096; + font-size: 12px; + line-height: 18px; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.regular-title-marker { + position: relative; + width: 9px; + height: 9px; + flex: 0 0 9px; + border: 2px solid #2d66ff; + border-radius: 2px; + background: #eaf2ff; + box-shadow: none; + + &.blue { + border-color: #2563eb; + box-shadow: 0 0 0 4px #e7f0ff; } } @@ -4876,46 +5098,82 @@ onUnmounted(() => { .regular-config-body { min-height: 0; overflow: auto; + background: #fff; padding: 14px; } .regular-file-fields { display: grid; gap: 12px; - margin-bottom: 12px; + margin-bottom: 14px; label { display: grid; - gap: 8px; + gap: 6px; + border: 0; + border-radius: 0; + background: transparent; + padding: 0; + box-shadow: none; } span { - color: #1f2937; + display: flex; + align-items: center; + gap: 7px; + color: #1d2b41; font-size: 13px; font-weight: 800; + + &::before { + display: none; + } } } .design-select { :deep(.n-base-selection) { + min-height: 34px; border-radius: 8px; + background: #fff; } } +.regular-rule-grid { + display: grid; + gap: 12px; +} + .design-card { + border: 1px solid #e4e9f2; border-radius: 8px; background: #fbfcff; padding: 14px; + box-shadow: none; & + & { - margin-top: 12px; + margin-top: 0; + } + + &.featured { + border-color: #e4e9f2; + background: #fbfcff; } header { - margin-bottom: 10px; + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; + + strong { + color: #152033; + font-size: 14px; + font-weight: 900; + } span { - color: #7f8aa0; + color: #8a97aa; font-size: 12px; letter-spacing: 0.12em; } @@ -4927,9 +5185,12 @@ onUnmounted(() => { } .design-inline-rule { - max-width: 420px; - grid-template-columns: auto auto 88px auto 88px; + max-width: 470px; + grid-template-columns: auto auto minmax(82px, 100px) auto minmax(82px, 100px); margin-bottom: 8px; + border-radius: 8px; + background: #f6f9fd; + padding: 8px 10px; } .regular-ai-line { @@ -4939,12 +5200,15 @@ onUnmounted(() => { min-height: 26px; button { - border: 0; - background: transparent; + height: 22px; + border: 1px solid #b9d2ff; + border-radius: 999px; + background: #eef5ff; color: #1e5eff; cursor: pointer; font-size: 12px; - padding: 0; + font-weight: 800; + padding: 0 10px; } em { @@ -4963,67 +5227,345 @@ onUnmounted(() => { } .regular-design-stats { - color: #273244; + flex: 1; + color: #616a79; + font-size: 12px; white-space: nowrap; + + strong { + margin: 0 2px; + color: #20242d; + font-size: 16px; + font-weight: 800; + } } .regular-design-actions { display: inline-flex; gap: 8px; - margin-left: 12px; + flex: 0 0 auto; + margin-left: 0; + white-space: nowrap; button { height: 28px; - border: 1px solid #d7deea; + min-width: 72px; + border: 1px solid #cfdcff; border-radius: 7px; background: #fff; - color: #3f4654; + color: #1f62ff; cursor: pointer; font-size: 12px; font-weight: 700; padding: 0 12px; white-space: nowrap; + word-break: keep-all; } button:hover { - border-color: #ffb165; - background: #fff7ed; - color: #d06f10; + border-color: #9bbcff; + background: #f3f7ff; + color: #185cff; + } + + button:disabled { + opacity: 0.65; + cursor: not-allowed; + } +} + +.regular-reanalyze-button { + width: 76px; + height: 32px; + border: 0; + border-radius: 8px; + background: linear-gradient(180deg, #ff9f22 0%, #ff8614 100%); + color: #fff; + cursor: pointer; + font-size: 13px; + font-weight: 700; + line-height: 32px; + padding: 0; + text-align: center; + white-space: nowrap; + word-break: keep-all; + + &:disabled { + opacity: 0.65; + cursor: not-allowed; } } .regular-result-area { min-height: 0; overflow: hidden; - padding: 12px; + background: #fff; + padding: 0; +} + +.design-result-stack { + display: grid; + grid-template-rows: minmax(126px, auto) minmax(0, 1fr); + gap: 10px; + padding: 10px; +} + +.design-table-block { + display: grid; + min-height: 0; + border: 1px solid #e3e8f2; + border-radius: 8px; + background: #fff; + overflow: hidden; +} + +.regular-reference-block { + grid-template-rows: 40px minmax(0, 1fr); +} + +.regular-analysis-result-block { + grid-template-rows: 40px minmax(0, 1fr); +} + +.design-table-block > header { + display: flex; + height: 40px; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid #edf1f6; + background: #fafbfd; + padding: 0 10px; + gap: 12px; +} + +.design-table-block > header strong { + display: inline-flex; + flex: 1 1 auto; + min-width: 0; + align-items: center; + gap: 6px; + color: #212734; + font-size: 14px; + font-weight: 800; + white-space: nowrap; + word-break: keep-all; +} + +.design-table-block > header strong::before { + width: 8px; + height: 8px; + border: 2px solid #2d66ff; + border-radius: 2px; + background: #eaf2ff; + content: ''; +} + +.design-table-scroll { + min-height: 0; + overflow: auto; +} + +.design-reference-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; +} + +.design-reference-table th:nth-child(1) { + width: 44px; +} + +.design-reference-table th:nth-child(2) { + width: 80px; +} + +.design-reference-table th:nth-child(4) { + width: 206px; +} + +.design-reference-table th { + height: 40px; + border: 1px solid #e8edf5; + background: #f7f8fb; + color: #313846; + font-weight: 700; + text-align: center; +} + +.design-reference-table td { + height: 40px; + border: 1px solid #edf1f6; + color: #384152; + text-align: center; +} + +.design-reference-table td:nth-child(3) { + text-align: left; + padding-left: 10px; +} + +.design-table-empty { + color: #7b8494 !important; + text-align: center !important; +} + +.design-analysis-table { + width: 100%; + table-layout: fixed; + border-collapse: collapse; + font-size: 13px; +} + +.design-analysis-table th { + height: 40px; + border: 1px solid #e8edf5; + background: #f7f8fb; + color: #313846; + font-weight: 700; + text-align: center; +} + +.design-analysis-table td { + height: 40px; + border: 1px solid #edf1f6; + color: #384152; + text-align: center; + word-break: break-all; +} + +.design-analysis-table th:nth-child(1), +.design-analysis-table td:nth-child(1) { + width: 44px; +} + +.design-analysis-table th:nth-child(2), +.design-analysis-table td:nth-child(2) { + width: 38px; +} + +.design-analysis-table th:nth-child(3), +.design-analysis-table td:nth-child(3) { + width: 78px; +} + +.design-analysis-table th:nth-child(4), +.design-analysis-table td:nth-child(4) { + width: 54px; +} + +.design-analysis-table th:nth-child(5), +.design-analysis-table td:nth-child(5), +.design-analysis-table th:nth-child(6), +.design-analysis-table td:nth-child(6) { + width: 104px; +} + +.design-analysis-table th:nth-child(7), +.design-analysis-table td:nth-child(7) { + width: 92px; +} + +.design-analysis-table th:nth-child(8), +.design-analysis-table td:nth-child(8) { + width: 126px; +} + +.design-analysis-table th:nth-child(9), +.design-analysis-table td:nth-child(9) { + width: 76px; +} + +.design-analysis-table th:nth-child(10), +.design-analysis-table td:nth-child(10) { + width: 104px; +} + +.design-analysis-table input[type='checkbox'] { + width: 14px; + height: 14px; + accent-color: #2d66ff; +} + +.analysis-risk-value { + color: #152033; + font-size: 28px; + font-weight: 900; + line-height: 1; +} + +.analysis-status { + display: inline-flex; + min-height: 24px; + align-items: center; + justify-content: center; + border-radius: 0; + background: #f1f5f9; + color: #64748b; + font-size: 12px; + line-height: 20px; + padding: 1px 4px; +} + +.analysis-status.success { + background: #e6f7e9; + color: #138a43; +} + +.analysis-status.pending { + background: #fff7ed; + color: #d06f10; +} + +.analysis-status.failed { + background: #fee2e2; + color: #dc2626; +} + +.design-analysis-actions-cell { + white-space: nowrap; +} + +.design-analysis-actions-cell button { + border: 0; + background: transparent; + color: #1f62ff; + cursor: pointer; + font-size: 12px; + padding: 0 3px; +} + +.design-analysis-actions-cell button.danger { + color: #e9364c; } .regular-result-scroll { width: 100%; height: 100%; min-width: 0; - overflow: auto; + overflow: hidden auto; } .regular-empty-result { display: grid; - min-height: 44px; + height: 100%; + min-height: 120px; align-content: center; justify-items: center; - border: 1px dashed #cfd8e8; - border-radius: 8px; - background: #fbfdff; - color: #667085; + border: 0; + border-radius: 0; + background: #fff; + color: #7b8494; + gap: 8px; text-align: center; strong { color: #20242d; - font-size: 14px; + font-size: 15px; font-weight: 900; } p { - margin: 6px 0 0; + margin: 0; font-size: 12px; } } @@ -5089,10 +5631,11 @@ onUnmounted(() => { .regular-setting-card { display: grid; gap: 12px; - border: 1px solid #e7ecf5; - border-radius: 12px; - background: linear-gradient(180deg, #ffffff 0%, #f9fbff 100%); + border: 1px solid #e4e9f2; + border-radius: 8px; + background: #fbfcff; padding: 14px; + box-shadow: none; header { display: flex; @@ -5233,6 +5776,10 @@ onUnmounted(() => { .regular-data-table { min-height: 0; min-width: 0; + border: 0; + border-radius: 0; + background: #fff; + overflow: hidden; :deep(.n-data-table) { min-width: 0; @@ -5245,40 +5792,52 @@ onUnmounted(() => { } :deep(.n-data-table-base-table-body) { - overflow: auto !important; + overflow: hidden auto !important; } :deep(.n-data-table-base-table-body table) { - min-width: max-content; + width: 100% !important; + min-width: 0 !important; + table-layout: fixed; } :deep(.n-data-table-th) { - height: 40px; + height: 42px; + border: 1px solid #e8edf5; background: #f7f8fb; - color: #303642; - font-weight: 800; + color: #313846; + font-weight: 700; + text-align: center; } :deep(.n-data-table-td) { - color: #333a46; - font-size: 12px; + height: 40px; + border: 1px solid #edf1f6; + color: #384152; + font-size: 13px; + text-align: center; + word-break: break-all; + } + + :deep(.n-data-table-tr:hover .n-data-table-td) { + background: #f8fbff; } } .regular-result-detail-table { width: 100%; - min-width: 1124px; + min-width: 0; :deep(.n-data-table-th), :deep(.n-data-table-td) { - white-space: nowrap; + white-space: normal; } } .analysis-actions { display: inline-flex; align-items: center; - gap: 8px; + gap: 4px; justify-content: center; white-space: nowrap; @@ -5322,12 +5881,12 @@ onUnmounted(() => { display: inline-flex !important; align-items: center; justify-content: center; - gap: 8px; + gap: 4px; white-space: nowrap; } :deep(.analysis-action-btn) { - min-width: 46px !important; + min-width: 42px !important; height: 26px !important; border: 1px solid #cfe0ff !important; border-radius: 999px !important; @@ -5337,7 +5896,7 @@ onUnmounted(() => { font-size: 12px !important; font-weight: 800 !important; line-height: 24px !important; - padding: 0 10px !important; + padding: 0 6px !important; box-shadow: none !important; } @@ -5376,133 +5935,148 @@ onUnmounted(() => { } .regular-filter-modal { - width: min(720px, 92vw); - border-radius: 16px; + width: 560px; + overflow: hidden; + border: 1px solid #ead9c1; + border-radius: 12px; + background: #fff; + box-shadow: 0 22px 44px rgba(17, 24, 39, 0.2); + + :deep(.n-card) { + overflow: hidden; + } :deep(.n-card-header) { - border-bottom: 1px solid #edf1f6; - padding: 20px 24px 16px; + height: 62px; + border-bottom: 1px solid #e4e9f2; + background: #fff; + padding: 0 20px; + } + + :deep(.n-card-header__main) { + display: flex; + align-items: center; + } + + :deep(.n-card-header__close) { + width: 28px; + height: 28px; + color: #666f80; + font-size: 20px; } :deep(.n-card__content) { - padding: 18px 24px; + padding: 16px 20px; } :deep(.n-card__footer) { - border-top: 1px solid #edf1f6; - padding: 16px 24px; + height: 62px; + border-top: 1px solid #e4e9f2; + background: #fff; + padding: 0 20px; } } .regular-filter-modal-head { - display: grid; - gap: 6px; + display: inline-flex; + align-items: center; + gap: 10px; - strong { - color: #152033; - font-size: 18px; - font-weight: 900; + .review-pattern-filter-title-bar { + width: 4px; + height: 18px; + border-radius: 2px; + background: #ff9f22; } - span { - color: #7e8798; - font-size: 12px; - font-weight: 400; + strong { + color: #1f2937; + font-size: 18px; + font-weight: 700; } } .regular-filter-modal-body { display: grid; gap: 12px; + color: #2f3644; + font-size: 14px; } -.regular-filter-option { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - align-items: center; - gap: 18px; - border: 1px solid #e7ecf5; - border-radius: 12px; - background: #fff; - padding: 14px 16px; - - strong { - display: block; - margin-bottom: 5px; - color: #20242d; - font-size: 14px; - font-weight: 900; - } - - p { - margin: 0; - color: #7e8798; - font-size: 12px; - line-height: 18px; - } -} - -.regular-filter-option.prominent { - border-color: #ffd7ac; - background: linear-gradient(180deg, #fffaf4 0%, #fff7ed 100%); -} - -.regular-filter-combo, -.regular-filter-keyinfo { - grid-template-columns: minmax(0, 1fr) minmax(220px, 300px); -} - -.regular-filter-control { - display: grid; - grid-template-columns: auto minmax(88px, 1fr) auto; +.regular-filter-row { + display: flex; + min-height: 24px; align-items: center; gap: 8px; - color: #667085; - font-size: 12px; + flex-wrap: wrap; + + input[type='checkbox'] { + width: 14px; + height: 14px; + accent-color: #ff9f22; + } } -.regular-filter-control.wide { - grid-template-columns: auto minmax(0, 1fr); +.regular-filter-row input[type='number'] { + width: 76px; + height: 28px; + border: 1px solid #e2d4c2; + border-radius: 8px; + background: #fff9f2; + padding: 0 8px; + color: #2f3644; + font-size: 14px; + outline: none; } -.regular-filter-select { - min-width: 0; +.regular-filter-select-shell { + display: inline-flex; + align-items: center; + min-width: 140px; + height: 28px; + border: 1px solid #e2d4c2; + border-radius: 8px; + background: #fff9f2; + padding: 0 8px; +} - :deep(.n-base-selection-tags) { - max-height: 66px; - overflow-y: auto; - } - - :deep(.n-tag__content) { - max-width: 84px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } +.regular-filter-select-shell select { + min-width: 124px; + height: 24px; + border: 0; + background: transparent; + padding: 0; + color: #2f3644; + font-size: 14px; + outline: none; } .regular-filter-modal-footer { display: flex; + height: 100%; + align-items: center; justify-content: flex-end; gap: 10px; button { - height: 32px; - border-radius: 8px; + min-width: 76px; + height: 34px; + border-radius: 6px; cursor: pointer; - font-weight: 800; + font-size: 14px; + font-weight: 700; padding: 0 18px; } button:first-child { - border: 1px solid #d7deea; - background: #fff; - color: #4f5b70; + border: 1px solid #ffd9a9; + background: #fff5e8; + color: #bd6a18; } button:last-child { border: 1px solid #ff9f22; - background: linear-gradient(180deg, #ff9f22 0%, #ff8614 100%); + background: linear-gradient(180deg, #ffb34b 0%, #ff8d1f 100%); color: #fff; } } @@ -5720,12 +6294,12 @@ onUnmounted(() => { border: 1px solid #e2e7f0; border-radius: 10px; background: #fff; + cursor: pointer; padding: 10px; strong { color: #242a35; font-size: 14px; - cursor: pointer; } p { @@ -5736,6 +6310,10 @@ onUnmounted(() => { } } +.review-history-action { + cursor: default; +} + .review-history-head { display: flex; align-items: center; @@ -5755,6 +6333,666 @@ onUnmounted(() => { gap: 10px; } +.review-pattern-compare-modal-overlay { + position: fixed; + inset: 0; + z-index: 3000; + display: flex; + align-items: flex-end; + justify-content: center; + background: rgba(18, 23, 34, 0.36); +} + +.review-pattern-compare-modal { + position: relative; + width: calc(100vw - 20px); + height: calc(100vh - 20px); + overflow: hidden; + border: 1px solid #ead9c1; + border-radius: 12px 12px 0 0; + background: #fff; + box-shadow: 0 -12px 26px rgba(17, 24, 39, 0.18); + animation: reviewSheetIn 0.24s ease; + + > header { + display: flex; + height: 52px; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid #e8edf5; + background: #fffdf8; + padding: 0 18px; + } +} + +@keyframes reviewSheetIn { + from { + transform: translateY(100%); + } + + to { + transform: translateY(0); + } +} + +.review-pattern-compare-tabs { + display: flex; + height: 100%; + align-items: center; + gap: 0; + + button { + position: relative; + height: 100%; + border: 0; + border-radius: 0; + background: transparent; + color: #4b5566; + cursor: pointer; + font-size: 14px; + font-weight: 700; + padding: 0 20px; + + &.active { + color: #1f62ff; + + &::after { + position: absolute; + right: 10px; + bottom: 0; + left: 10px; + height: 2px; + background: #1f62ff; + content: ''; + } + } + } +} + +.review-pattern-compare-header-actions { + display: inline-flex; + align-items: center; + gap: 8px; +} + +.review-pattern-compare-close, +.review-pattern-compare-save { + display: inline-flex; + min-width: 64px; + height: 32px; + align-items: center; + justify-content: center; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + font-weight: 700; + line-height: 1; + padding: 0 12px; +} + +.review-pattern-compare-close { + border: 1px solid #ffd9a9; + background: #fff5e8; + color: #bd6a18; +} + +.review-pattern-compare-save { + min-width: 82px; + border: 1px solid #ff9f22; + background: linear-gradient(180deg, #ffb34b 0%, #ff8d1f 100%); + color: #fff; +} + +.review-pattern-compare-body { + display: grid; + height: calc(100% - 52px); + min-height: 0; + grid-template-columns: 260px minmax(0, 1fr); +} + +.review-pattern-compare-body.real-detail-body { + display: block; + overflow: hidden; + background: #f6f8fc; + padding: 14px 10px 16px; + + .module { + height: 100% !important; + overflow: hidden !important; + padding: 0 !important; + } + + .module-wrapper { + box-sizing: border-box; + height: 100% !important; + gap: 14px !important; + padding: 0 14px !important; + } + + .module-wrapper-sider { + width: 230px !important; + flex: 0 0 230px !important; + overflow: hidden; + border: 1px solid #dbe3ef; + border-radius: 4px !important; + background: #fff !important; + } + + .module-wrapper-sider-search { + padding: 14px 14px 10px !important; + } + + .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; + } + + .module-wrapper-sider-content { + margin-top: 0 !important; + overflow: hidden !important; + } + + .module-wrapper-sider-content .n-card { + border-radius: 0 !important; + background: #fff !important; + } + + .module-wrapper-sider-content .n-card-header { + min-height: 42px; + border-bottom: 1px solid #e8edf5; + padding: 0 10px !important; + } + + .module-wrapper-sider-content .n-card__content { + padding: 0 !important; + } + + .module-wrapper-content { + min-width: 0; + flex: 1 1 0 !important; + width: auto !important; + overflow: hidden; + border: 1px solid #dbe3ef; + border-radius: 0 !important; + background: #fff !important; + } + + .module-wrapper-content-card { + border-radius: 0 !important; + } + + .module-wrapper-content-card-header { + position: relative; + display: flex !important; + height: 34px !important; + align-items: center; + border-bottom: 1px solid #e8edf5 !important; + background: #fff !important; + padding-left: 86px !important; + padding-right: 10px !important; + + .n-text { + display: block; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .module-wrapper-content-card-content { + margin-top: 0 !important; + } + + .module-wrapper-content-card-content-title { + height: 34px; + border-bottom: 1px solid #eef2f7; + background: #fff !important; + color: #5e6777; + font-size: 12px; + padding: 0 10px !important; + } + + .module-wrapper-content-card-content-body { + overflow: auto !important; + border-radius: 0 !important; + background: #737373; + } + + .module-wrapper-content-card .gradient-1::before, + .module-wrapper-content-card .gradient-2::before { + top: 5px !important; + left: 10px !important; + width: 64px !important; + height: 24px !important; + border-radius: 4px !important; + line-height: 24px !important; + box-sizing: border-box; + padding: 0 6px; + text-align: center; + white-space: nowrap; + } + + .module-wrapper-content-card .gradient-1::before { + background: linear-gradient(180deg, #5f90ff 0%, #3064df 100%) !important; + } + + .module-wrapper-content-card .gradient-2::before { + background: linear-gradient(180deg, #ffbe62 0%, #ff8d1f 100%) !important; + } + + .module-footer { + display: none !important; + } +} + +.review-pattern-compare-left { + display: grid; + min-height: 0; + grid-template-rows: auto auto auto minmax(0, 1fr); + border-right: 1px solid #e8edf5; + background: #f8fafd; + padding: 14px; + + &.text-mode { + .review-pattern-compare-search { + display: none; + } + } +} + +.review-pattern-compare-stat { + display: block; + margin-bottom: 8px; + + .text-result-head { + border: 1px solid #dfe6f2; + border-radius: 8px 8px 0 0; + background: linear-gradient(180deg, #eef4ff 0%, #e8f0ff 100%); + padding: 10px; + + strong { + display: block; + color: #2a3345; + font-size: 16px; + margin-bottom: 6px; + } + + p { + margin: 0; + color: #4a5568; + font-size: 12px; + } + + b { + color: #e6362a; + } + } + + .text-result-summary { + display: flex; + height: 36px; + align-items: center; + justify-content: space-between; + border: 1px solid #dfe6f2; + border-top: 0; + border-radius: 0 0 8px 8px; + background: #fff; + color: #4d5768; + font-size: 12px; + padding: 0 10px; + } + + .summary-switch { + display: inline-flex; + align-items: center; + gap: 6px; + } + + .text-summary-nav { + width: 22px; + height: 22px; + border: 1px solid #dfe6f2; + border-radius: 4px; + background: #fff; + color: #4e5668; + cursor: pointer; + } +} + +.review-pattern-compare-search { + display: grid; + grid-template-columns: minmax(0, 1fr) 34px; + gap: 6px; + margin-bottom: 10px; + + input { + height: 32px; + border: 1px solid #e2d4c2; + border-radius: 6px; + background: #fff9f2; + padding: 0 10px; + } + + button { + border: 1px solid #d8deea; + border-radius: 6px; + background: #fff; + } +} + +.review-pattern-compare-list-head { + position: sticky; + z-index: 2; + top: 0; + display: grid; + height: 36px; + grid-template-columns: 42px 84px minmax(0, 1fr); + align-items: center; + border: 1px solid #e2e7f0; + border-bottom: 0; + background: #f0f3f8; + font-size: 12px; + font-weight: 700; + padding: 0 8px; +} + +.review-pattern-compare-list { + min-height: 0; + overflow: auto; + border: 1px solid #e2e7f0; + + &.text-mode { + border: 0; + background: transparent; + } + + > button { + display: grid; + width: 100%; + height: 34px; + grid-template-columns: 42px 84px minmax(0, 1fr); + align-items: center; + border: 0; + border-bottom: 1px solid #edf1f6; + background: #fff; + cursor: pointer; + font-size: 12px; + padding: 0 8px; + text-align: left; + + &.active { + background: #eaf2ff; + color: #1f62ff; + } + + span:last-child { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } +} + +.text-result-group { + border: 1px solid #dfe6f2; + background: #fff; + margin-bottom: 8px; +} + +.text-result-group-head { + display: grid; + width: 100%; + height: 34px; + grid-template-columns: 14px minmax(0, 1fr) auto; + align-items: center; + gap: 6px; + border: 0; + border-bottom: 1px solid #edf1f6; + background: #fff; + cursor: pointer; + padding: 0 8px; + + .arrow { + color: #6e7788; + font-size: 12px; + } + + b { + overflow: hidden; + color: #2c3444; + font-size: 13px; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; + } + + em { + color: #ef3535; + font-size: 12px; + font-style: normal; + font-weight: 700; + } +} + +.text-result-group-list { + max-height: 250px; + overflow: auto; +} + +.text-result-item { + display: grid; + width: 100%; + height: 30px; + grid-template-columns: 10px minmax(0, 1fr); + align-items: center; + gap: 6px; + border: 0; + border-bottom: 1px solid #f0f3f8; + background: #fff; + cursor: pointer; + padding: 0 8px; + + span { + overflow: hidden; + color: #3f485a; + font-size: 12px; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; + } + + &.active { + background: #e8f0ff; + } +} + +.dot-green, +.dot-red { + display: inline-block; + width: 9px; + height: 9px; + border-radius: 999px; +} + +.dot-green { + background: #20b45a; +} + +.dot-red { + background: #ef3535; +} + +.review-pattern-compare-docs { + display: grid; + min-height: 0; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 12px; + background: #f7f9fc; + padding: 14px; + + article { + display: grid; + min-height: 0; + grid-template-rows: 34px 34px minmax(0, 1fr); + border: 1px solid #e2e7f0; + background: #fff; + } + + .doc-head { + display: flex; + align-items: center; + gap: 8px; + border-bottom: 1px solid #eef2f7; + font-size: 14px; + font-weight: 700; + padding: 0 10px; + + b { + display: inline-block; + border-radius: 4px; + background: linear-gradient(180deg, #5f90ff 0%, #3064df 100%); + color: #fff; + font-size: 12px; + padding: 2px 8px; + + &.compare-tag { + background: linear-gradient(180deg, #ffbe62 0%, #ff8d1f 100%); + } + } + } + + .doc-subhead { + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid #eef2f7; + color: #5e6777; + font-size: 12px; + padding: 0 10px; + } + + .doc-paper { + overflow: auto; + border: 1px solid #e4e9f2; + background: #737373; + margin: 10px; + padding: 14px; + } + + .compare-doc-canvas { + display: grid; + min-height: 100%; + gap: 14px; + } + + .compare-doc-a4-page { + display: grid; + width: min(520px, 100%); + min-height: 740px; + grid-auto-rows: min-content; + gap: 10px; + border: 1px solid #e3e7ef; + background: #fff; + box-shadow: 0 2px 8px rgba(17, 24, 39, 0.12); + margin: 0 auto; + padding: 24px 26px; + + > header { + color: #2b3342; + font-size: 18px; + font-weight: 700; + margin-bottom: 8px; + text-align: center; + } + + > footer { + color: #7a8394; + font-size: 12px; + margin-top: 12px; + text-align: center; + } + } + + .compare-doc-line { + border-radius: 4px; + color: #3f4858; + font-size: 13px; + line-height: 1.8; + margin: 0; + padding: 2px 6px; + + &.active { + background: #fff2db; + box-shadow: inset 0 0 0 1px rgba(255, 157, 35, 0.35); + color: #1f2a3c; + } + } + + .compare-doc-a4-page.image-mode { + gap: 12px; + } + + .compare-doc-image-block { + display: grid; + grid-template-columns: 108px minmax(0, 1fr); + gap: 10px; + border: 1px solid #e6ddcf; + border-radius: 8px; + background: #fffdf8; + margin: 0; + padding: 8px; + + &.active { + border-color: #ffcf8a; + background: #fff2db; + box-shadow: inset 0 0 0 1px rgba(255, 157, 35, 0.35); + } + } + + .compare-doc-image-thumb { + display: grid; + width: 108px; + height: 86px; + place-items: center; + border: 1px solid #dfe5f0; + border-radius: 6px; + background: linear-gradient(135deg, #dfe8ff 0%, #c6d7ff 100%); + color: #2f3746; + font-size: 12px; + font-weight: 700; + + &.reference { + background: linear-gradient(135deg, #ffe6c7 0%, #ffd19a 100%); + } + } + + .compare-doc-image-block figcaption { + display: grid; + min-width: 0; + align-content: center; + gap: 6px; + + b { + overflow: hidden; + color: #2b3342; + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; + } + + p { + margin: 0; + color: #5f6878; + font-size: 12px; + } + } +} + @media (max-width: 960px) { .workspace { padding: 18px 16px 24px; @@ -5811,13 +7049,46 @@ onUnmounted(() => { .review-columns, .responsive-review-columns, - .review-reupload-layout { + .review-reupload-layout, + .regular-analysis-workbench { display: flex; height: auto; min-height: 100vh; flex-direction: column; } + .regular-analysis-workbench { + padding: 10px; + } + + .regular-config-panel, + .regular-design-result-panel { + min-height: 360px; + } + + .regular-config-toolbar, + .regular-result-toolbar { + flex-wrap: wrap; + align-items: flex-start; + } + + .regular-design-stats { + width: 100%; + flex: 1 0 100%; + justify-content: flex-start; + overflow-x: auto; + } + + .regular-design-actions { + width: 100%; + overflow-x: auto; + } + + .design-inline-rule { + display: flex; + flex-wrap: wrap; + } + .review-rule-panel, .review-check-panel, .review-result-panel, @@ -5834,5 +7105,41 @@ onUnmounted(() => { .response-rule-panel { grid-template-rows: auto minmax(260px, auto) minmax(220px, auto); } + + .review-pattern-compare-modal { + width: 100vw; + height: 100vh; + border-radius: 0; + } + + .review-pattern-compare-modal > header { + height: auto; + min-height: 52px; + flex-wrap: wrap; + gap: 8px; + padding: 8px 12px; + } + + .review-pattern-compare-tabs { + width: 100%; + height: 40px; + overflow-x: auto; + } + + .review-pattern-compare-body { + height: calc(100% - 96px); + grid-template-columns: 1fr; + grid-template-rows: 220px minmax(0, 1fr); + } + + .review-pattern-compare-left { + border-right: 0; + border-bottom: 1px solid #e8edf5; + } + + .review-pattern-compare-docs { + grid-template-columns: 1fr; + overflow: auto; + } } diff --git a/src/views/ai-review/tech-proposal-redesign/regular-analysis/index.vue b/src/views/ai-review/tech-proposal-redesign/regular-analysis/index.vue index 048219c..1204d1a 100644 --- a/src/views/ai-review/tech-proposal-redesign/regular-analysis/index.vue +++ b/src/views/ai-review/tech-proposal-redesign/regular-analysis/index.vue @@ -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 ''; +};