Prechádzať zdrojové kódy

明细页面展示实现

肖栋 1 týždeň pred
rodič
commit
86625dacbd

+ 1 - 1
src/components/layout/AppSidebar.vue

@@ -38,7 +38,7 @@ const menuGroups = [
     label: "项目管理",
     children: [
       { key: "overview", label: "项目概览", routeName: "overview" },
-      { key: "detail", label: "项目明细", routeName: "projectDetail" },
+      { key: "particulars", label: "项目明细", routeName: "particulars" },
       { key: "map", label: "一张图", routeName: "oneMap" },
       { key: "plan", label: "总体计划", routeName: "overallPlan" },
     ],

+ 144 - 70
src/pages/home/overview.vue

@@ -267,14 +267,16 @@
               ? 'early_warning_report'
               : 'late_report'
           "
-          size="20px"
+          size="24px"
         />
         <span class="page-overview-report-dialog-title">
           {{ reportDialogType === "warning" ? "预警报告" : "滞后报告" }}
-          <span
-            class="page-overview-report-dialog-count"
-            :class="`is-${reportDialogType}`"
-            >({{ reportDialogList.length }})</span
+          <span class="page-overview-report-dialog-count-wrap"
+            >(<span
+              class="page-overview-report-dialog-count"
+              :class="`is-${reportDialogType}`"
+              >{{ reportDialogList.length }}</span
+            >)</span
           >
         </span>
       </div>
@@ -286,39 +288,45 @@
         :key="item.id"
         class="page-overview-report-item"
       >
-        <div class="page-overview-report-item-name">{{ item.projectName }}</div>
-        <div class="page-overview-report-item-grid">
-          <div class="page-overview-report-field is-full">
-            <span class="label">报告名称:</span>
-            <span class="value">{{ item.reportName }}</span>
-          </div>
-          <div class="page-overview-report-field">
-            <span class="label">开始时间:</span>
-            <span class="value">{{ item.startTime }}</span>
-          </div>
-          <div class="page-overview-report-field">
-            <span class="label">工期:</span>
-            <span class="value">{{ item.duration }}</span>
-          </div>
-          <div class="page-overview-report-field">
-            <span class="label">计划完成时间:</span>
-            <span class="value">{{ item.planEndTime }}</span>
-          </div>
-          <div class="page-overview-report-field">
-            <span class="label">{{
-              reportDialogType === "warning" ? "距完成天数:" : "已逾期天数:"
-            }}</span>
-            <span class="value" :class="`is-${reportDialogType}`"
-              >{{ item.days }} 天</span
-            >
+        <div class="page-overview-report-item-title">{{ item.projectName }}</div>
+        <div class="page-overview-report-item-body">
+          <div class="page-overview-report-row">
+            <div class="page-overview-report-field">
+              <span class="label">报告名称:</span>
+              <span class="value">{{ item.reportName }}</span>
+            </div>
           </div>
-          <div class="page-overview-report-field">
-            <span class="label">报告编制单位:</span>
-            <span class="value">{{ item.unit }}</span>
+          <div class="page-overview-report-row is-cols-4">
+            <div class="page-overview-report-field">
+              <span class="label">开始时间:</span>
+              <span class="value">{{ item.startTime }}</span>
+            </div>
+            <div class="page-overview-report-field">
+              <span class="label">工期:</span>
+              <span class="value">{{ item.duration }}</span>
+            </div>
+            <div class="page-overview-report-field">
+              <span class="label">计划完成时间:</span>
+              <span class="value">{{ item.planEndTime }}</span>
+            </div>
+            <div class="page-overview-report-field">
+              <span class="label">{{
+                reportDialogType === "warning" ? "距完成天数:" : "已逾期天数:"
+              }}</span>
+              <span class="value" :class="`is-${reportDialogType}`"
+                >{{ item.days }}天</span
+              >
+            </div>
           </div>
-          <div class="page-overview-report-field">
-            <span class="label">负责人:</span>
-            <span class="value">{{ item.owner }}</span>
+          <div class="page-overview-report-row is-cols-2">
+            <div class="page-overview-report-field">
+              <span class="label">报告编制单位:</span>
+              <span class="value">{{ item.unit }}</span>
+            </div>
+            <div class="page-overview-report-field">
+              <span class="label">负责人:</span>
+              <span class="value">{{ item.owner }}</span>
+            </div>
           </div>
         </div>
       </div>
@@ -326,7 +334,13 @@
 
     <template #footer>
       <div class="page-overview-report-dialog-footer">
-        <el-button @click="reportDialogVisible = false">关闭</el-button>
+        <button
+          type="button"
+          class="page-overview-report-dialog-close-btn"
+          @click="reportDialogVisible = false"
+        >
+          关闭
+        </button>
       </div>
     </template>
   </el-dialog>
@@ -1326,43 +1340,64 @@ const projectList = [
 }
 
 .page-overview-report-dialog.el-dialog {
+  --el-dialog-padding-primary: 0;
+  padding: 0;
+  overflow: hidden;
   border-radius: 4px;
 
   .el-dialog__header {
     margin: 0;
     padding: 16px 20px;
+    background: #ffffff;
     border-bottom: 1px solid #e5ebf3;
   }
 
+  .el-dialog__headerbtn {
+    top: 16px;
+    right: 20px;
+    width: 24px;
+    height: 24px;
+    margin: 0;
+
+    .el-dialog__close {
+      font-size: 24px;
+      color: #9aa5b8;
+    }
+  }
+
   .el-dialog__body {
-    padding: 16px 20px;
+    margin: 0;
+    padding: 16px;
+    background: #f6f9fd;
   }
 
   .el-dialog__footer {
-    padding: 12px 20px 20px;
+    margin: 0;
+    padding: 12px;
+    background: #ffffff;
+    border-top: 1px solid #e5ebf3;
   }
 }
 
 .page-overview-report-dialog-header {
   display: flex;
   align-items: center;
-  gap: 8px;
+  gap: 10px;
 }
 
 .page-overview-report-dialog-title {
   font-family: PingFang SC, PingFang SC;
   font-weight: 600;
-  font-size: 16px;
+  font-size: 18px;
   color: #16213a;
-  line-height: 22px;
+  line-height: 25px;
+  text-align: left;
+  font-style: normal;
 }
 
 .page-overview-report-dialog-count {
   font-weight: 600;
-
-  &.is-warning {
-    color: #ff8e38;
-  }
+  color: #ff8e38;
 
   &.is-delay {
     color: #f54848;
@@ -1372,74 +1407,99 @@ const projectList = [
 .page-overview-report-dialog-body {
   display: flex;
   flex-direction: column;
-  gap: 12px;
+  gap: 16px;
   max-height: 60vh;
   overflow-y: auto;
 }
 
 .page-overview-report-item {
-  padding: 16px;
-  background: #f6f9fd;
+  overflow: hidden;
+  background: #ffffff;
   border-radius: 4px;
 }
 
-.page-overview-report-item-name {
+.page-overview-report-item-title {
   position: relative;
-  margin-bottom: 12px;
-  padding-left: 10px;
+  padding: 14px 8px 14px 12px;
   font-family: PingFang SC, PingFang SC;
   font-weight: 600;
   font-size: 14px;
-  color: #16213a;
+  color: #58657c;
   line-height: 20px;
+  text-align: left;
 
   &::before {
     position: absolute;
-    top: 2px;
+    top: 50%;
     left: 0;
-    width: 3px;
+    width: 4px;
     height: 14px;
     background: #2382e7;
-    border-radius: 1px;
+    border-radius: 0 2px 2px 0;
+    transform: translateY(-50%);
     content: "";
   }
 }
 
-.page-overview-report-item-grid {
+.page-overview-report-item-body {
   display: flex;
-  flex-wrap: wrap;
-  gap: 8px 24px;
+  flex-direction: column;
+  gap: 16px;
+  padding: 0 8px 14px 12px;
 }
 
-.page-overview-report-field {
+.page-overview-report-row {
   display: flex;
-  align-items: baseline;
-  min-width: 160px;
-  font-family: PingFang SC, PingFang SC;
-  font-size: 13px;
-  line-height: 20px;
+  align-items: flex-start;
+  justify-content: flex-start;
+  flex-wrap: nowrap;
+  gap: 24px;
+  width: 100%;
 
-  &.is-full {
-    width: 100%;
-    min-width: 100%;
+  &.is-cols-4,
+  &.is-cols-2 {
+    .page-overview-report-field {
+      flex: 0 0 auto;
+      min-width: 0;
+    }
   }
+}
+
+.page-overview-report-field {
+  display: flex;
+  align-items: baseline;
+  flex-shrink: 0;
+  gap: 8px;
+  min-width: 0;
+  white-space: nowrap;
+  text-align: left;
 
   .label {
     flex-shrink: 0;
+    font-family: PingFang SC, PingFang SC;
+    font-weight: 400;
+    font-size: 14px;
     color: #9aa5b8;
+    line-height: 20px;
+    text-align: left;
   }
 
   .value {
+    flex-shrink: 0;
+    font-family: PingFang SC, PingFang SC;
+    font-weight: 400;
+    font-size: 14px;
     color: #16213a;
+    line-height: 20px;
+    text-align: left;
+    white-space: nowrap;
 
     &.is-warning {
       color: #ff8e38;
-      font-weight: 600;
     }
 
     &.is-delay {
       color: #f54848;
-      font-weight: 600;
     }
   }
 }
@@ -1448,4 +1508,18 @@ const projectList = [
   display: flex;
   justify-content: center;
 }
+
+.page-overview-report-dialog-close-btn {
+  padding: 6px 16px;
+  font-family: PingFang SC, PingFang SC;
+  font-weight: 400;
+  font-size: 14px;
+  color: #58657c;
+  line-height: 20px;
+  text-align: left;
+  background: #ffffff;
+  border: 1px solid #e4eaf2;
+  border-radius: 2px;
+  cursor: pointer;
+}
 </style>

+ 657 - 0
src/pages/home/particulars.vue

@@ -0,0 +1,657 @@
+<template>
+  <div class="page-particulars">
+    <div class="page-particulars-header">
+      <h2 class="page-particulars-title">项目明细</h2>
+      <div class="page-particulars-actions">
+        <button type="button" class="page-particulars-btn is-outline">
+          导出Word
+        </button>
+        <button type="button" class="page-particulars-btn is-primary">
+          <icon-svg name="" size="16px" />
+          <span>新增项目</span>
+        </button>
+      </div>
+    </div>
+
+    <div class="page-particulars-panel">
+      <div class="page-particulars-panel-header">
+        <div class="page-particulars-panel-left">
+          <div class="page-particulars-panel-title">项目列表</div>
+          <div class="page-particulars-legend">
+            <span
+              v-for="item in tableLegend"
+              :key="item.key"
+              class="page-particulars-legend-item"
+            >
+              <i
+                class="page-particulars-legend-dot"
+                :class="`is-${item.key}`"
+              ></i>
+              {{ item.label }}
+            </span>
+          </div>
+        </div>
+        <el-select v-model="listFilter" size="small" style="width: 120px">
+          <el-option
+            v-for="opt in listFilterOptions"
+            :key="opt.value"
+            :label="opt.label"
+            :value="opt.value"
+          />
+        </el-select>
+      </div>
+
+      <div class="page-particulars-table-scroll">
+        <table class="page-particulars-table">
+          <thead>
+            <tr>
+              <th rowspan="2" class="col-name">项目名称</th>
+              <th rowspan="2" class="col-risk">环境风险</th>
+              <th colspan="4" class="group-feasibility group-title">可行性研究</th>
+              <th colspan="4" class="group-basic group-title">基础设计</th>
+              <th colspan="4" class="group-detail group-title">详细设计/建造安装</th>
+              <th rowspan="2" class="col-action">操作</th>
+            </tr>
+            <tr>
+              <th
+                v-for="col in phaseSubColumns"
+                :key="`f-${col.key}`"
+                class="group-feasibility"
+              >
+                {{ col.label }}
+              </th>
+              <th
+                v-for="col in phaseSubColumns"
+                :key="`b-${col.key}`"
+                class="group-basic"
+              >
+                {{ col.label }}
+              </th>
+              <th
+                v-for="col in phaseSubColumns"
+                :key="`d-${col.key}`"
+                class="group-detail"
+              >
+                {{ col.label }}
+              </th>
+            </tr>
+          </thead>
+          <tbody>
+            <template v-for="(row, rowIndex) in tableRows" :key="rowIndex">
+              <tr v-if="row.isGap" class="page-particulars-gap-row">
+                <td colspan="15"></td>
+              </tr>
+              <tr v-else>
+                <td
+                  v-if="row.isFirst"
+                  class="col-name"
+                  :rowspan="row.rowspan"
+                >
+                  {{ row.project.name }}
+                </td>
+                <td
+                  v-if="row.isFirst"
+                  class="col-risk"
+                  :rowspan="row.rowspan"
+                >
+                  {{ row.project.risk }}
+                </td>
+
+                <td>{{ row.feasibility?.name || "—" }}</td>
+                <td :class="dateClass(row.feasibility?.planStatus)">
+                  {{ formatDate(row.feasibility?.planTime) }}
+                </td>
+                <td :class="dateClass(row.feasibility?.actualStatus)">
+                  {{ formatDate(row.feasibility?.actualTime) }}
+                </td>
+                <td>{{ row.feasibility?.unit || "—" }}</td>
+
+                <td>{{ row.basic?.name || "—" }}</td>
+                <td :class="dateClass(row.basic?.planStatus)">
+                  {{ formatDate(row.basic?.planTime) }}
+                </td>
+                <td :class="dateClass(row.basic?.actualStatus)">
+                  {{ formatDate(row.basic?.actualTime) }}
+                </td>
+                <td>{{ row.basic?.unit || "—" }}</td>
+
+                <td>{{ row.detail?.name || "—" }}</td>
+                <td :class="dateClass(row.detail?.planStatus)">
+                  {{ formatDate(row.detail?.planTime) }}
+                </td>
+                <td :class="dateClass(row.detail?.actualStatus)">
+                  {{ formatDate(row.detail?.actualTime) }}
+                </td>
+                <td>{{ row.detail?.unit || "—" }}</td>
+
+                <td
+                  v-if="row.isFirst"
+                  class="col-action"
+                  :rowspan="row.rowspan"
+                >
+                  <div class="page-particulars-ops">
+                    <button type="button" class="page-particulars-op-btn">
+                      明细
+                    </button>
+                    <button type="button" class="page-particulars-op-btn">
+                      进展
+                    </button>
+                  </div>
+                </td>
+              </tr>
+            </template>
+          </tbody>
+        </table>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { computed, ref } from "vue";
+
+defineOptions({
+  name: "ProjectParticulars",
+});
+
+const tableLegend = [
+  { key: "warning", label: "预警" },
+  { key: "delay", label: "滞后" },
+];
+
+const listFilter = ref("all");
+const listFilterOptions = [
+  { label: "全部", value: "all" },
+  { label: "预警", value: "warning" },
+  { label: "滞后", value: "delay" },
+];
+
+const phaseSubColumns = [
+  { key: "name", label: "报告名称" },
+  { key: "planTime", label: "计划完成时间" },
+  { key: "actualTime", label: "实际完成时间" },
+  { key: "unit", label: "报告编制单位" },
+];
+
+const projectList = [
+  {
+    id: 1,
+    name: "垦利10-1油田开发项目",
+    risk: "环境风险较大",
+    feasibility: [
+      {
+        name: "环境质量现状调查",
+        planTime: "2026-03-15",
+        actualTime: "2026-03-12",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "渔业资源现状调查",
+        planTime: "2026-04-20",
+        actualTime: "2026-04-22",
+        actualStatus: "delay",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "环境风险预评价",
+        planTime: "2026-05-10",
+        actualTime: "2026-05-08",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "桌面路由方案",
+        planTime: "2026-06-01",
+        actualTime: "2026-05-28",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "通航安全影响咨询",
+        planTime: "2026-07-30",
+        actualTime: "",
+        unit: "邦厉有限公司",
+      },
+    ],
+    basic: [
+      {
+        name: "安全预评价",
+        planTime: "2026-03-20",
+        actualTime: "2026-03-18",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "职业病危害预评价",
+        planTime: "2026-04-15",
+        actualTime: "2026-04-16",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "环境影响报告",
+        planTime: "2026-05-20",
+        actualTime: "2026-05-22",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "海域使用论证",
+        planTime: "2026-06-10",
+        actualTime: "2026-06-12",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "海洋倾废论证",
+        planTime: "2026-07-05",
+        actualTime: "",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "航道通航条件影响评价",
+        planTime: "2026-08-01",
+        actualTime: "",
+        unit: "邦厉有限公司",
+      },
+    ],
+    detail: [
+      {
+        name: "详细设计审查",
+        planTime: "2026-09-01",
+        actualTime: "",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "设备采购",
+        planTime: "2026-10-01",
+        actualTime: "",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "建造安装",
+        planTime: "2026-11-01",
+        actualTime: "",
+        unit: "邦厉有限公司",
+      },
+      {
+        name: "竣工验收",
+        planTime: "2026-12-01",
+        actualTime: "",
+        unit: "邦厉有限公司",
+      },
+    ],
+  },
+  {
+    id: 2,
+    name: "蓬莱19-3油田开发项目",
+    risk: "环境风险一般",
+    feasibility: [
+      {
+        name: "环境质量现状调查",
+        planTime: "2026-08-30",
+        planStatus: "warning",
+        actualTime: "",
+        unit: "海蓝工程咨询",
+      },
+      {
+        name: "环境影响评价",
+        planTime: "2026-09-15",
+        actualTime: "",
+        unit: "海蓝工程咨询",
+      },
+    ],
+    basic: [
+      {
+        name: "安全预评价",
+        planTime: "2026-10-01",
+        actualTime: "",
+        unit: "海蓝工程咨询",
+      },
+    ],
+    detail: [
+      {
+        name: "详细设计",
+        planTime: "2026-11-01",
+        actualTime: "",
+        unit: "海蓝工程咨询",
+      },
+    ],
+  },
+  {
+    id: 3,
+    name: "中新天津生态城水系提升项目",
+    risk: "环境风险较小",
+    feasibility: [
+      {
+        name: "可行性研究报告",
+        planTime: "2026-05-01",
+        actualTime: "2026-04-28",
+        unit: "生态城研究院",
+      },
+    ],
+    basic: [
+      {
+        name: "基本设计审查",
+        planTime: "2026-06-01",
+        actualTime: "2026-06-03",
+        unit: "生态城研究院",
+      },
+    ],
+    detail: [
+      {
+        name: "详细设计/建造安装",
+        planTime: "2026-08-01",
+        actualTime: "",
+        unit: "生态城研究院",
+      },
+    ],
+  },
+];
+
+const getProjectRowCount = (project) =>
+  Math.max(
+    project.feasibility?.length || 0,
+    project.basic?.length || 0,
+    project.detail?.length || 0,
+    1,
+  );
+
+const tableRows = computed(() => {
+  const rows = [];
+  projectList.forEach((project) => {
+    rows.push({ isGap: true });
+    const rowspan = getProjectRowCount(project);
+    for (let i = 0; i < rowspan; i += 1) {
+      rows.push({
+        project,
+        isFirst: i === 0,
+        rowspan,
+        feasibility: project.feasibility[i] || null,
+        basic: project.basic[i] || null,
+        detail: project.detail[i] || null,
+      });
+    }
+  });
+  return rows;
+});
+
+const formatDate = (value) => value || "—";
+
+const dateClass = (status) => {
+  if (status === "warning") return "is-warning";
+  if (status === "delay") return "is-delay";
+  return "";
+};
+</script>
+
+<style scoped lang="scss">
+.page-particulars {
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+  width: 100%;
+  min-height: 100%;
+  padding: 24px;
+  background: #f3f7fc;
+}
+
+.page-particulars-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 16px;
+}
+
+.page-particulars-title {
+  margin: 0;
+  font-family: PingFang SC, PingFang SC;
+  font-weight: 600;
+  font-size: 18px;
+  color: #16213a;
+  line-height: 25px;
+  text-align: left;
+}
+
+.page-particulars-actions {
+  display: flex;
+  align-items: center;
+  gap: 24px;
+}
+
+.page-particulars-btn {
+  display: inline-flex;
+  align-items: center;
+  padding: 6px 16px;
+  font-family: PingFang SC, PingFang SC;
+  font-weight: 500;
+  font-size: 14px;
+  line-height: 20px;
+  text-align: left;
+  border-radius: 2px;
+  box-shadow: 0px 4px 10px 0px rgba(35, 130, 231, 0.2);
+  cursor: pointer;
+
+  &.is-outline {
+    color: #2382e7;
+    background: #ffffff;
+    border: 1px solid #2382e7;
+
+    &:hover {
+      border-color: #2382e7;
+    }
+  }
+
+  &.is-primary {
+    gap: 4px;
+    color: #ffffff;
+    background: #2382e7;
+    border: 1px solid #2382e7;
+
+    &:hover {
+      border-color: #2382e7;
+    }
+  }
+}
+
+.page-particulars-panel {
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  gap: 14px;
+  padding: 16px;
+  background: #ffffff;
+  border-radius: 4px;
+}
+
+.page-particulars-panel-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 16px;
+}
+
+.page-particulars-panel-left {
+  display: flex;
+  align-items: center;
+  gap: 16px;
+  min-width: 0;
+}
+
+.page-particulars-panel-title {
+  position: relative;
+  padding-left: 10px;
+  font-family: PingFang SC, PingFang SC;
+  font-weight: 600;
+  font-size: 14px;
+  color: #16213a;
+  line-height: 20px;
+
+  &::before {
+    position: absolute;
+    top: 50%;
+    left: 0;
+    width: 4px;
+    height: 14px;
+    background: #2382e7;
+    border-radius: 0 2px 2px 0;
+    transform: translateY(-50%);
+    content: "";
+  }
+}
+
+.page-particulars-legend {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.page-particulars-legend-item {
+  display: inline-flex;
+  align-items: center;
+  gap: 4px;
+  font-size: 14px;
+  color: #9aa5b8;
+  line-height: 20px;
+  white-space: nowrap;
+}
+
+.page-particulars-legend-dot {
+  width: 6px;
+  height: 6px;
+  border-radius: 50%;
+  background: #d0d5dd;
+
+  &.is-warning {
+    background: #ff8e38;
+  }
+
+  &.is-delay {
+    background: #f54848;
+  }
+}
+
+.page-particulars-table-scroll {
+  width: 100%;
+  overflow-x: auto;
+}
+
+.page-particulars-table {
+  width: 100%;
+  min-width: 1400px;
+  border-collapse: separate;
+  border-spacing: 0;
+  table-layout: fixed;
+  font-size: 13px;
+  color: #16213a;
+
+  th,
+  td {
+    box-sizing: border-box;
+    padding: 10px 12px;
+    border: 1px solid #dfe3e7;
+    text-align: left;
+    vertical-align: middle;
+    word-break: break-word;
+    background: #ffffff;
+  }
+
+  th {
+    font-family: PingFang SC, PingFang SC;
+    font-weight: 400;
+    font-size: 14px;
+    color: #58657c;
+    background: #edf1f6;
+    white-space: nowrap;
+    word-break: keep-all;
+  }
+
+  .group-feasibility {
+    background: #e8f3fc;
+  }
+
+  .group-basic {
+    background: #e9f7ef;
+  }
+
+  .group-detail {
+    background: #eef0fb;
+  }
+
+  .group-title {
+    text-align: center;
+  }
+
+  .col-name,
+  .col-risk,
+  .col-action {
+    position: sticky;
+    z-index: 2;
+  }
+
+  th.col-name,
+  th.col-risk,
+  th.col-action {
+    z-index: 4;
+    background: #edf1f6;
+  }
+
+  td.col-name,
+  td.col-risk,
+  td.col-action {
+    background: #ffffff;
+  }
+
+  .col-name {
+    left: 0;
+    width: 140px;
+    min-width: 140px;
+  }
+
+  .col-risk {
+    left: 140px;
+    width: 100px;
+    min-width: 100px;
+    box-shadow: 2px 0 6px rgba(22, 33, 58, 0.08);
+  }
+
+  .col-action {
+    right: 0;
+    width: 100px;
+    min-width: 100px;
+    box-shadow: -2px 0 6px rgba(22, 33, 58, 0.08);
+  }
+
+  td.is-warning {
+    color: #ff8e38;
+  }
+
+  td.is-delay {
+    color: #f54848;
+  }
+
+  .page-particulars-gap-row td {
+    height: 16px;
+    padding: 0;
+    border: none;
+    background: transparent;
+  }
+}
+
+.page-particulars-ops {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+  gap: 8px;
+}
+
+.page-particulars-op-btn {
+  padding: 0;
+  font-family: PingFang SC, PingFang SC;
+  font-size: 13px;
+  color: #2382e7;
+  line-height: 18px;
+  background: transparent;
+  border: none;
+  cursor: pointer;
+
+  &:hover {
+    border-color: transparent;
+  }
+}
+</style>

+ 3 - 3
src/router/index.js

@@ -23,9 +23,9 @@ const routes = [
         },
       },
       {
-        path: "project-detail",
-        name: "projectDetail",
-        component: () => import("@/pages/empty/index.vue"),
+        path: "particulars",
+        name: "particulars",
+        component: () => import("@/pages/home/particulars.vue"),
         meta: {
           title: "项目明细",
         },