Przeglądaj źródła

fix(frontend): standardize facility edit drawers

Kazerin 1 tydzień temu
rodzic
commit
22ce365cff

+ 8 - 0
memory/sessions/2026-08-28.md

@@ -0,0 +1,8 @@
+
+## T1 编辑抽屉与操作列验收修正
+
+- 五类供水设施查询页面(管网、泵站、水厂、水源地、用水户)的新增/修改表单统一改为右侧 `el-drawer`,保留既有字段、校验、权限和提交接口。
+- 表格操作列统一为带 tooltip、无障碍标签和悬停反馈的详情/修改/删除图标按钮;公共样式支持编辑抽屉滚动、移动端全宽。
+- 新增 `detailDrawerRule.test.mjs` 断言覆盖五个页面的编辑抽屉及操作列钩子。
+- 验证:T1 抽屉专项 3/3,全量 Node 测试 15/15,`npm run build:prod` 通过;仅有既有 Sass 弃用警告。
+- 代码审查:相对 `origin/master`,本轮目标文件无明确标准或规格硬违规;测试规则可进一步增强动态详情弹窗覆盖,五页操作列存在可选组件抽取的重复代码气味。

+ 58 - 0
src/assets/styles/index.scss

@@ -4,6 +4,64 @@
 @import './element-ui.scss';
 @import './sidebar.scss';
 @import './btn.scss';
+
+// Read-only detail content opens from the right across all business modules.
+.detail-drawer {
+  max-width: 100vw;
+}
+
+.detail-drawer .el-drawer__body {
+  overflow-y: auto;
+  overflow-x: hidden;
+}
+
+.detail-drawer .el-descriptions__content,
+.detail-drawer .detail-content,
+.detail-drawer .detail-info,
+.detail-drawer .desc-text {
+  overflow-wrap: anywhere;
+  word-break: break-word;
+}
+
+@media (max-width: 768px) {
+  .detail-drawer,
+  .facility-form-drawer {
+    width: 100% !important;
+  }
+}
+
+.facility-form-drawer .el-drawer__body {
+  overflow-y: auto;
+  padding: 20px 24px 12px;
+}
+
+.facility-form-drawer .el-drawer__footer {
+  padding: 14px 24px;
+  border-top: 1px solid #e5edf7;
+  background: #f8fbff;
+}
+
+.facility-row-actions {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+}
+
+.facility-row-action.el-button {
+  width: 30px;
+  height: 30px;
+  margin: 0;
+  border-width: 1px;
+  box-shadow: 0 2px 5px rgba(31, 78, 121, 0.1);
+  transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+.facility-row-action.el-button:hover,
+.facility-row-action.el-button:focus-visible {
+  transform: translateY(-1px);
+  box-shadow: 0 4px 9px rgba(31, 78, 121, 0.18);
+}
 @import './ruoyi.scss';
 
 body {

+ 12 - 10
src/views/subSystem/basic/pipeInfo/index.vue

@@ -97,11 +97,13 @@
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="160" />
-      <el-table-column label="操作" align="center" width="180" fixed="right">
+      <el-table-column label="操作" align="center" width="168" fixed="right">
         <template #default="{ row }">
-          <el-button size="small" type="text" icon="View" @click="handleDetail(row)">详情</el-button>
-          <el-button size="small" type="text" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:pipeInfo:edit']">修改</el-button>
-          <el-button size="small" type="text" icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:pipeInfo:remove']">删除</el-button>
+          <div class="facility-row-actions">
+            <el-tooltip content="查看详情" placement="top"><el-button class="facility-row-action is-detail" aria-label="查看详情" size="small" type="primary" plain circle icon="View" @click="handleDetail(row)" /></el-tooltip>
+            <el-tooltip content="修改信息" placement="top"><el-button class="facility-row-action is-edit" aria-label="修改信息" size="small" type="warning" plain circle icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:pipeInfo:edit']" /></el-tooltip>
+            <el-tooltip content="删除记录" placement="top"><el-button class="facility-row-action is-delete" aria-label="删除记录" size="small" type="danger" plain circle icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:pipeInfo:remove']" /></el-tooltip>
+          </div>
         </template>
       </el-table-column>
     </el-table>
@@ -109,8 +111,8 @@
     <!-- 分页 -->
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
 
-    <!-- 新增/修改对话框 -->
-    <el-dialog :title="dialogTitle" v-model="dialogVisible" width="700px" append-to-body>
+    <!-- 新增/修改抽屉 -->
+    <el-drawer :title="dialogTitle" v-model="dialogVisible" class="facility-form-drawer" direction="rtl" size="720px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="108px">
         <el-row :gutter="20">
           <el-col :span="12">
@@ -183,10 +185,10 @@
         <el-button type="primary" @click="submitForm">确 定</el-button>
         <el-button @click="dialogVisible = false">取 消</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
-    <!-- 详情对话框 -->
-    <el-dialog title="管网详情" v-model="detailVisible" width="600px" append-to-body>
+    <!-- 详情抽屉 -->
+    <el-drawer title="管网详情" v-model="detailVisible" class="detail-drawer" direction="rtl" size="600px" append-to-body>
       <el-descriptions :column="2" border>
         <el-descriptions-item label="管网编号">{{ detailData.pipeCode }}</el-descriptions-item>
         <el-descriptions-item label="管网名称">{{ detailData.pipeName }}</el-descriptions-item>
@@ -211,7 +213,7 @@
       <template #footer>
         <el-button @click="detailVisible = false">关 闭</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
     <!-- 回收站对话框 -->
     <el-dialog title="回收站" v-model:visible="recycleVisible" width="900px" append-to-body>

+ 12 - 10
src/views/subSystem/basic/pumpStation/index.vue

@@ -76,11 +76,13 @@
       <el-table-column label="负责人" align="center" prop="principal" width="100" />
       <el-table-column label="联系电话" align="center" prop="contactPhone" width="120" />
       <el-table-column label="创建时间" align="center" prop="createTime" width="160" />
-      <el-table-column label="操作" align="center" width="180" fixed="right">
+      <el-table-column label="操作" align="center" width="168" fixed="right">
         <template #default="{ row }">
-          <el-button size="small" type="text" icon="View" @click="handleDetail(row)">详情</el-button>
-          <el-button size="small" type="text" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:pumpStation:edit']">修改</el-button>
-          <el-button size="small" type="text" icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:pumpStation:remove']">删除</el-button>
+          <div class="facility-row-actions">
+            <el-tooltip content="查看详情" placement="top"><el-button class="facility-row-action is-detail" aria-label="查看详情" size="small" type="primary" plain circle icon="View" @click="handleDetail(row)" /></el-tooltip>
+            <el-tooltip content="修改信息" placement="top"><el-button class="facility-row-action is-edit" aria-label="修改信息" size="small" type="warning" plain circle icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:pumpStation:edit']" /></el-tooltip>
+            <el-tooltip content="删除记录" placement="top"><el-button class="facility-row-action is-delete" aria-label="删除记录" size="small" type="danger" plain circle icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:pumpStation:remove']" /></el-tooltip>
+          </div>
         </template>
       </el-table-column>
     </el-table>
@@ -88,8 +90,8 @@
     <!-- 分页 -->
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
 
-    <!-- 新增/修改对话框 -->
-    <el-dialog :title="dialogTitle" v-model="dialogVisible" width="750px" append-to-body>
+    <!-- 新增/修改抽屉 -->
+    <el-drawer :title="dialogTitle" v-model="dialogVisible" class="facility-form-drawer" direction="rtl" size="760px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="110px">
         <el-row :gutter="20">
           <el-col :span="12">
@@ -162,10 +164,10 @@
         <el-button type="primary" @click="submitForm">确 定</el-button>
         <el-button @click="dialogVisible = false">取 消</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
-    <!-- 详情对话框 -->
-    <el-dialog title="泵站详情" v-model="detailVisible" width="650px" append-to-body>
+    <!-- 详情抽屉 -->
+    <el-drawer title="泵站详情" v-model="detailVisible" class="detail-drawer" direction="rtl" size="650px" append-to-body>
       <el-descriptions :column="2" border>
         <el-descriptions-item label="泵站编号">{{ detailData.stationCode }}</el-descriptions-item>
         <el-descriptions-item label="泵站名称">{{ detailData.stationName }}</el-descriptions-item>
@@ -189,7 +191,7 @@
       <template #footer>
         <el-button @click="detailVisible = false">关 闭</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
     <!-- 回收站对话框 -->
     <el-dialog title="回收站" v-model="recycleVisible" width="900px" append-to-body>

+ 12 - 10
src/views/subSystem/basic/waterPlant/index.vue

@@ -76,11 +76,13 @@
       <el-table-column label="负责人" align="center" prop="principal" width="100" />
       <el-table-column label="联系电话" align="center" prop="contactPhone" width="120" />
       <el-table-column label="创建时间" align="center" prop="createTime" width="160" />
-      <el-table-column label="操作" align="center" width="180" fixed="right">
+      <el-table-column label="操作" align="center" width="168" fixed="right">
         <template #default="{ row }">
-          <el-button size="small" type="text" icon="View" @click="handleDetail(row)">详情</el-button>
-          <el-button size="small" type="text" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:waterPlant:edit']">修改</el-button>
-          <el-button size="small" type="text" icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:waterPlant:remove']">删除</el-button>
+          <div class="facility-row-actions">
+            <el-tooltip content="查看详情" placement="top"><el-button class="facility-row-action is-detail" aria-label="查看详情" size="small" type="primary" plain circle icon="View" @click="handleDetail(row)" /></el-tooltip>
+            <el-tooltip content="修改信息" placement="top"><el-button class="facility-row-action is-edit" aria-label="修改信息" size="small" type="warning" plain circle icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:waterPlant:edit']" /></el-tooltip>
+            <el-tooltip content="删除记录" placement="top"><el-button class="facility-row-action is-delete" aria-label="删除记录" size="small" type="danger" plain circle icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:waterPlant:remove']" /></el-tooltip>
+          </div>
         </template>
       </el-table-column>
     </el-table>
@@ -88,8 +90,8 @@
     <!-- 分页 -->
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
 
-    <!-- 新增/修改对话框 -->
-    <el-dialog :title="dialogTitle" v-model="dialogVisible" width="750px" append-to-body>
+    <!-- 新增/修改抽屉 -->
+    <el-drawer :title="dialogTitle" v-model="dialogVisible" class="facility-form-drawer" direction="rtl" size="760px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="130px">
         <el-row :gutter="20">
           <el-col :span="12">
@@ -166,10 +168,10 @@
         <el-button type="primary" @click="submitForm">确 定</el-button>
         <el-button @click="dialogVisible = false">取 消</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
-    <!-- 详情对话框 -->
-    <el-dialog title="水厂详情" v-model="detailVisible" width="650px" append-to-body>
+    <!-- 详情抽屉 -->
+    <el-drawer title="水厂详情" v-model="detailVisible" class="detail-drawer" direction="rtl" size="650px" append-to-body>
       <el-descriptions :column="2" border>
         <el-descriptions-item label="水厂编号">{{ detailData.plantCode }}</el-descriptions-item>
         <el-descriptions-item label="水厂名称">{{ detailData.plantName }}</el-descriptions-item>
@@ -194,7 +196,7 @@
       <template #footer>
         <el-button @click="detailVisible = false">关 闭</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
     <!-- 回收站对话框 -->
     <el-dialog title="回收站" v-model="recycleVisible" width="900px" append-to-body>

+ 12 - 10
src/views/subSystem/basic/waterSource/index.vue

@@ -74,11 +74,13 @@
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="160" />
-      <el-table-column label="操作" align="center" width="180" fixed="right">
+      <el-table-column label="操作" align="center" width="168" fixed="right">
         <template #default="{ row }">
-          <el-button size="small" type="text" icon="View" @click="handleDetail(row)">详情</el-button>
-          <el-button size="small" type="text" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:waterSource:edit']">修改</el-button>
-          <el-button size="small" type="text" icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:waterSource:remove']">删除</el-button>
+          <div class="facility-row-actions">
+            <el-tooltip content="查看详情" placement="top"><el-button class="facility-row-action is-detail" aria-label="查看详情" size="small" type="primary" plain circle icon="View" @click="handleDetail(row)" /></el-tooltip>
+            <el-tooltip content="修改信息" placement="top"><el-button class="facility-row-action is-edit" aria-label="修改信息" size="small" type="warning" plain circle icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:waterSource:edit']" /></el-tooltip>
+            <el-tooltip content="删除记录" placement="top"><el-button class="facility-row-action is-delete" aria-label="删除记录" size="small" type="danger" plain circle icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:waterSource:remove']" /></el-tooltip>
+          </div>
         </template>
       </el-table-column>
     </el-table>
@@ -86,8 +88,8 @@
     <!-- 分页 -->
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
 
-    <!-- 新增/修改对话框 -->
-    <el-dialog :title="dialogTitle" v-model="dialogVisible" width="750px" append-to-body>
+    <!-- 新增/修改抽屉 -->
+    <el-drawer :title="dialogTitle" v-model="dialogVisible" class="facility-form-drawer" direction="rtl" size="760px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="110px">
         <el-row :gutter="20">
           <el-col :span="12">
@@ -172,10 +174,10 @@
         <el-button type="primary" @click="submitForm">确 定</el-button>
         <el-button @click="dialogVisible = false">取 消</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
-    <!-- 详情对话框 -->
-    <el-dialog title="水源地详情" v-model="detailVisible" width="650px" append-to-body>
+    <!-- 详情抽屉 -->
+    <el-drawer title="水源地详情" v-model="detailVisible" class="detail-drawer" direction="rtl" size="650px" append-to-body>
       <el-descriptions :column="2" border>
         <el-descriptions-item label="水源地ID">{{ detailData.sourceId }}</el-descriptions-item>
         <el-descriptions-item label="水源地名称">{{ detailData.sourceName }}</el-descriptions-item>
@@ -199,7 +201,7 @@
       <template #footer>
         <el-button @click="detailVisible = false">关 闭</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
     <!-- 回收站对话框 -->
     <el-dialog title="回收站" v-model="recycleVisible" width="900px" append-to-body>

+ 12 - 10
src/views/subSystem/basic/waterUserInfo/index.vue

@@ -81,11 +81,13 @@
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="160" />
-      <el-table-column label="操作" align="center" width="180" fixed="right">
+      <el-table-column label="操作" align="center" width="168" fixed="right">
         <template #default="{ row }">
-          <el-button size="small" type="text" icon="View" @click="handleDetail(row)">详情</el-button>
-          <el-button size="small" type="text" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:waterUser:edit']">修改</el-button>
-          <el-button size="small" type="text" icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:waterUser:remove']">删除</el-button>
+          <div class="facility-row-actions">
+            <el-tooltip content="查看详情" placement="top"><el-button class="facility-row-action is-detail" aria-label="查看详情" size="small" type="primary" plain circle icon="View" @click="handleDetail(row)" /></el-tooltip>
+            <el-tooltip content="修改信息" placement="top"><el-button class="facility-row-action is-edit" aria-label="修改信息" size="small" type="warning" plain circle icon="Edit" @click="handleUpdate(row)" v-hasPermi="['waterSupply:waterUser:edit']" /></el-tooltip>
+            <el-tooltip content="删除记录" placement="top"><el-button class="facility-row-action is-delete" aria-label="删除记录" size="small" type="danger" plain circle icon="Delete" @click="handleDelete(row)" v-hasPermi="['waterSupply:waterUser:remove']" /></el-tooltip>
+          </div>
         </template>
       </el-table-column>
     </el-table>
@@ -93,8 +95,8 @@
     <!-- 分页 -->
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
 
-    <!-- 新增/修改对话框 -->
-    <el-dialog :title="dialogTitle" v-model="dialogVisible" width="750px" append-to-body>
+    <!-- 新增/修改抽屉 -->
+    <el-drawer :title="dialogTitle" v-model="dialogVisible" class="facility-form-drawer" direction="rtl" size="760px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="110px">
         <el-row :gutter="20">
           <el-col :span="12">
@@ -172,10 +174,10 @@
         <el-button type="primary" @click="submitForm">确 定</el-button>
         <el-button @click="dialogVisible = false">取 消</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
-    <!-- 详情对话框 -->
-    <el-dialog title="用水户详情" v-model="detailVisible" width="650px" append-to-body>
+    <!-- 详情抽屉 -->
+    <el-drawer title="用水户详情" v-model="detailVisible" class="detail-drawer" direction="rtl" size="650px" append-to-body>
       <el-descriptions :column="2" border>
         <el-descriptions-item label="用水户编号">{{ detailData.userCode }}</el-descriptions-item>
         <el-descriptions-item label="用水户名称">{{ detailData.userName }}</el-descriptions-item>
@@ -199,7 +201,7 @@
       <template #footer>
         <el-button @click="detailVisible = false">关 闭</el-button>
       </template>
-    </el-dialog>
+    </el-drawer>
 
     <!-- 回收站对话框 -->
     <el-dialog title="回收站" v-model="recycleVisible" width="900px" append-to-body>

+ 57 - 0
tests/detailDrawerRule.test.mjs

@@ -0,0 +1,57 @@
+import assert from 'node:assert/strict'
+import { readdir, readFile } from 'node:fs/promises'
+import { join } from 'node:path'
+import test from 'node:test'
+
+async function listVueFiles(directory) {
+  const entries = await readdir(directory, { withFileTypes: true })
+  const files = await Promise.all(entries.map(entry => {
+    const path = join(directory, entry.name)
+    return entry.isDirectory() ? listVueFiles(path) : path.endsWith('.vue') ? [path] : []
+  }))
+  return files.flat()
+}
+
+test('all read-only detail views use the shared right-side drawer', async () => {
+  const views = await listVueFiles('src/views')
+  for (const view of views) {
+    const source = await readFile(view, 'utf8')
+    const detailDialogs = source.match(/<el-dialog\b[^>]*(?:详情|详细|查看|预览|报警位置地图|视频查看|研判分析|催办记录|监测告警联动|全屏监控)[^>]*>/gu) || []
+    assert.deepEqual(detailDialogs, [], view)
+
+    const drawers = source.match(/<el-drawer\b[^>]*>/gu) || []
+    for (const drawer of drawers) {
+      assert.match(drawer, /direction=["']rtl["']/u, `${view}: ${drawer}`)
+      if (!drawer.includes('facility-form-drawer')) {
+        assert.match(drawer, /class=["'][^"']*detail-drawer/u, `${view}: ${drawer}`)
+      }
+    }
+  }
+})
+
+test('operation forms remain dialogs instead of being treated as read-only details', async () => {
+  const devicePage = await readFile('src/views/subSystem/waterSupply/components/WaterDevicePage.vue', 'utf8')
+
+  const alarmPage = await readFile('src/views/subSystem/waterSupply/components/WaterAlarmPage.vue', 'utf8')
+  assert.match(devicePage, /<el-dialog[^>]*title="设备维修派单"/u)
+  assert.match(alarmPage, /<el-dialog[^>]*title="报警维修派单"/u)
+})
+
+test('water facility edit forms and table actions use the shared drawer and action styles', async () => {
+  const facilityViews = [
+    'src/views/subSystem/basic/pipeInfo/index.vue',
+    'src/views/subSystem/basic/pumpStation/index.vue',
+    'src/views/subSystem/basic/waterPlant/index.vue',
+    'src/views/subSystem/basic/waterSource/index.vue',
+    'src/views/subSystem/basic/waterUserInfo/index.vue'
+  ]
+
+  for (const view of facilityViews) {
+    const source = await readFile(view, 'utf8')
+    assert.match(source, /<el-drawer[^>]*:title="dialogTitle"[^>]*class="facility-form-drawer"[^>]*direction="rtl"/u, view)
+    assert.match(source, /class="facility-row-actions"/u, view)
+    assert.match(source, /class="facility-row-action is-detail"/u, view)
+    assert.match(source, /class="facility-row-action is-edit"/u, view)
+    assert.match(source, /class="facility-row-action is-delete"/u, view)
+  }
+})