|
|
@@ -89,9 +89,9 @@
|
|
|
<el-table-column label="发布人" prop="publisher" width="120" />
|
|
|
<el-table-column label="状态" width="120" align="center">
|
|
|
<template #default="scope">
|
|
|
- <el-tag :type="getStatusTagType(scope.row.status)">
|
|
|
+ <WarningStatusTag :status="scope.row.status">
|
|
|
{{ getStatusText(scope.row.status) }}
|
|
|
- </el-tag>
|
|
|
+ </WarningStatusTag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="操作" fixed="right" width="280" align="center">
|
|
|
@@ -290,7 +290,11 @@
|
|
|
<span v-else>-</span>
|
|
|
</el-descriptions-item>
|
|
|
<el-descriptions-item label="发布时间">{{ formatDateTime(detailData.basicInfo.publishTime) }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="状态">{{ getStatusText(detailData.basicInfo.status) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="状态">
|
|
|
+ <WarningStatusTag :status="detailData.basicInfo.status">
|
|
|
+ {{ getStatusText(detailData.basicInfo.status) }}
|
|
|
+ </WarningStatusTag>
|
|
|
+ </el-descriptions-item>
|
|
|
<el-descriptions-item label="内容描述" :span="2"><span class="warning-content">{{ detailData.basicInfo.warningContent || "-" }}</span></el-descriptions-item>
|
|
|
<el-descriptions-item label="备注" :span="2">{{ detailData.basicInfo.remark || "-" }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
@@ -385,7 +389,10 @@
|
|
|
</el-dialog>
|
|
|
|
|
|
<!-- 处置人选择对话框 -->
|
|
|
- <el-dialog v-model="userPickerVisible" :title="pickerTarget === 'reviewer' ? '选择核查人' : '选择处置人'" width="900px" append-to-body @open="loadUserPickerData">
|
|
|
+ <el-dialog v-model="userPickerVisible" :title="pickerTarget === 'reviewer' ? '选择核查人' : '选择处置人'" width="900px" append-to-body @open="loadUserPickerData" @closed="closeUserPicker">
|
|
|
+ <el-alert v-if="userPickerError" :title="userPickerError" type="error" :closable="false" show-icon style="margin-bottom: 12px">
|
|
|
+ <el-button link type="primary" @click="loadUserPickerData">重新加载</el-button>
|
|
|
+ </el-alert>
|
|
|
<div class="user-picker-container">
|
|
|
<!-- 左侧部门树 -->
|
|
|
<div class="user-picker-left">
|
|
|
@@ -394,6 +401,7 @@
|
|
|
<el-tree
|
|
|
ref="deptTreeRef"
|
|
|
:data="deptTree"
|
|
|
+ node-key="id"
|
|
|
:props="{ label: 'label', children: 'children' }"
|
|
|
:filter-node-method="filterDeptNode"
|
|
|
:highlight-current="true"
|
|
|
@@ -407,25 +415,28 @@
|
|
|
用户列表
|
|
|
<span v-if="currentDeptName" class="current-dept">({{ currentDeptName }})</span>
|
|
|
</div>
|
|
|
- <el-input v-model="userFilterText" placeholder="搜索用户" clearable style="margin-bottom: 12px;" @input="filterUserList" />
|
|
|
+ <el-input v-model="userFilterText" placeholder="搜索账号或姓名,回车查询" maxlength="100" clearable style="margin-bottom: 12px;" @keyup.enter="searchPickerUsers" @clear="searchPickerUsers">
|
|
|
+ <template #append><el-button :icon="Search" @click="searchPickerUsers" /></template>
|
|
|
+ </el-input>
|
|
|
<el-table
|
|
|
v-loading="userPickerLoading"
|
|
|
- :data="filteredUserList"
|
|
|
+ :data="userList"
|
|
|
highlight-current-row
|
|
|
@current-change="handleUserCurrentChange"
|
|
|
- height="400"
|
|
|
+ height="320"
|
|
|
+ empty-text="当前部门没有可选的启用人员,可切换其他部门或全部部门"
|
|
|
>
|
|
|
<el-table-column label="用户名称" prop="userName" min-width="120" show-overflow-tooltip />
|
|
|
<el-table-column label="用户昵称" prop="nickName" min-width="120" show-overflow-tooltip />
|
|
|
<el-table-column label="部门" prop="deptName" min-width="140" show-overflow-tooltip />
|
|
|
- <el-table-column label="手机号码" prop="phonenumber" width="130" />
|
|
|
</el-table>
|
|
|
+ <pagination v-show="userTotal > 0" :total="userTotal" v-model:page="userPage.pageNum" v-model:limit="userPage.pageSize" :auto-scroll="false" layout="total, prev, pager, next" @pagination="loadUserList" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
|
<el-button @click="userPickerVisible = false">取 消</el-button>
|
|
|
- <el-button type="primary" :disabled="!selectedUser" @click="confirmSelectUser">确 定</el-button>
|
|
|
+ <el-button type="primary" :disabled="!selectedUser || userPickerLoading || !!userPickerError" @click="confirmSelectUser">确 定</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
@@ -433,6 +444,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
+import WarningStatusTag from "../components/WarningStatusTag.vue"
|
|
|
import { useWarningStatuses } from '@/views/subSystem/lifeCompany/warningWorkflow'
|
|
|
const { warningStatusOptions, databaseStatusLabels } = useWarningStatuses()
|
|
|
import WarningItemSummary from '../components/WarningItemSummary.vue';
|
|
|
@@ -443,7 +455,6 @@ import { parseTime } from "@/utils/ruoyi";
|
|
|
import WarningDisposalReasons from '../components/WarningDisposalReasons.vue';
|
|
|
import WarningAttachments from "../components/WarningAttachments.vue";
|
|
|
import { attachmentsForDisposal, unlinkedWarningAttachments } from "../warningAttachments";
|
|
|
-import { deptTreeSelect, listUser } from "@/api/system/user";
|
|
|
import { listEquipment, listEquipmentTypeAll } from "@/api/pipeNetwork/pdeviceInform";
|
|
|
import {
|
|
|
deleteYjxxData,
|
|
|
@@ -452,6 +463,8 @@ import {
|
|
|
getWarningDetailData,
|
|
|
getWarningReasonListData,
|
|
|
getWarningItemListData,
|
|
|
+ getWarningParticipantDepartments,
|
|
|
+ getWarningParticipants,
|
|
|
releaseYjxxData,
|
|
|
submitYjxxData,
|
|
|
updateYjxxData
|
|
|
@@ -498,7 +511,13 @@ const deviceQuery = reactive({
|
|
|
// 用户选择器相关
|
|
|
const deptTree = ref([]);
|
|
|
const userList = ref([]);
|
|
|
-const filteredUserList = ref([]);
|
|
|
+const userTotal = ref(0);
|
|
|
+const userPage = reactive({ pageNum: 1, pageSize: 10 });
|
|
|
+const deptPickerError = ref("");
|
|
|
+const userListError = ref("");
|
|
|
+const userPickerError = computed(() => deptPickerError.value || userListError.value);
|
|
|
+let userRequestVersion = 0;
|
|
|
+let deptRequestVersion = 0;
|
|
|
const selectedDeptId = ref("");
|
|
|
const currentDeptName = ref("");
|
|
|
const selectedUser = ref(null);
|
|
|
@@ -649,18 +668,6 @@ function getStatusText(status) {
|
|
|
return databaseStatusLabels.value[status] || status || "-"
|
|
|
}
|
|
|
|
|
|
-function getStatusTagType(status) {
|
|
|
- // 按照预警状态语义设置 tag 颜色
|
|
|
- return {
|
|
|
- DRAFT: "info", // 草稿 - 灰色(未发布)
|
|
|
- PENDING: "warning", // 待办 - 黄色(等待处置)
|
|
|
- RECEIVED: "warning", // 已接收 - 黄色
|
|
|
- PROCESSING: "warning", // 处置中 - 黄色(进行中)
|
|
|
- HANDLED: "success", // 已处置 - 绿色(已完成)
|
|
|
- CLOSED: "info" // 已解除 - 灰色
|
|
|
- }[status] || "info";
|
|
|
-}
|
|
|
-
|
|
|
function normalizeWarningRow(item) {
|
|
|
const row = { ...item };
|
|
|
row.itemId = item.itemId || item.item_id || "";
|
|
|
@@ -775,6 +782,7 @@ async function loadList() {
|
|
|
warningNo: queryParams.warningNo,
|
|
|
warningType: queryParams.warningType,
|
|
|
warningLevel: queryParams.warningLevel,
|
|
|
+ releaseOrder: true,
|
|
|
startTime: queryParams.dateRange?.[0] || "",
|
|
|
endTime: queryParams.dateRange?.[1] || ""
|
|
|
};
|
|
|
@@ -816,57 +824,61 @@ function filterDeptNode(value, data) {
|
|
|
|
|
|
// 用户选择器相关函数
|
|
|
async function loadUserPickerData() {
|
|
|
- userPickerLoading.value = true;
|
|
|
+ const version = ++deptRequestVersion;
|
|
|
+ deptPickerError.value = "";
|
|
|
+ userList.value = [];
|
|
|
+ userTotal.value = 0;
|
|
|
+ selectedUser.value = null;
|
|
|
+ userPage.pageNum = 1;
|
|
|
+ selectedDeptId.value = "";
|
|
|
+ currentDeptName.value = "全部部门";
|
|
|
+ deptTree.value = [];
|
|
|
+ const users = loadUserList();
|
|
|
try {
|
|
|
- await loadDeptTree();
|
|
|
- // 默认加载第一个部门的用户
|
|
|
- if (deptTree.value.length > 0) {
|
|
|
- const firstDept = deptTree.value[0];
|
|
|
- selectedDeptId.value = firstDept.id;
|
|
|
- currentDeptName.value = firstDept.label;
|
|
|
- await loadUserList(firstDept.id);
|
|
|
- }
|
|
|
- } finally {
|
|
|
- userPickerLoading.value = false;
|
|
|
+ const res = await getWarningParticipantDepartments();
|
|
|
+ if (version !== deptRequestVersion || !userPickerVisible.value) return;
|
|
|
+ deptTree.value = [{ id: '', label: '全部部门', children: res.data || [] }];
|
|
|
+ } catch {
|
|
|
+ if (version === deptRequestVersion && userPickerVisible.value) deptPickerError.value = "部门加载失败,请重新加载";
|
|
|
}
|
|
|
+ await users;
|
|
|
}
|
|
|
|
|
|
-async function loadDeptTree() {
|
|
|
- const res = await deptTreeSelect();
|
|
|
- deptTree.value = res.data || [];
|
|
|
-}
|
|
|
-
|
|
|
-async function loadUserList(deptId) {
|
|
|
+async function loadUserList() {
|
|
|
+ const version = ++userRequestVersion;
|
|
|
userPickerLoading.value = true;
|
|
|
+ userListError.value = "";
|
|
|
+ selectedUser.value = null;
|
|
|
+ userList.value = [];
|
|
|
+ userTotal.value = 0;
|
|
|
try {
|
|
|
- const res = await listUser({ deptId, pageNum: 1, pageSize: 100 });
|
|
|
- userList.value = res.rows || [];
|
|
|
- filteredUserList.value = userList.value;
|
|
|
+ const res = await getWarningParticipants({ ...userPage, deptId: selectedDeptId.value || undefined, keyword: userFilterText.value.trim() || undefined });
|
|
|
+ if (version !== userRequestVersion || !userPickerVisible.value) return;
|
|
|
+ userList.value = res.data?.records || [];
|
|
|
+ userTotal.value = Number(res.data?.total || 0);
|
|
|
+ } catch {
|
|
|
+ if (version === userRequestVersion && userPickerVisible.value) userListError.value = "人员加载失败,请重新加载";
|
|
|
} finally {
|
|
|
- userPickerLoading.value = false;
|
|
|
+ if (version === userRequestVersion) userPickerLoading.value = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function handleDeptClick(data) {
|
|
|
selectedDeptId.value = data.id;
|
|
|
currentDeptName.value = data.label;
|
|
|
- loadUserList(data.id);
|
|
|
- selectedUser.value = null;
|
|
|
- userFilterText.value = "";
|
|
|
+ searchPickerUsers();
|
|
|
}
|
|
|
|
|
|
-function filterUserList() {
|
|
|
- const keyword = userFilterText.value.toLowerCase();
|
|
|
- if (!keyword) {
|
|
|
- filteredUserList.value = userList.value;
|
|
|
- return;
|
|
|
- }
|
|
|
- filteredUserList.value = userList.value.filter((user) => {
|
|
|
- const userName = (user.userName || "").toLowerCase();
|
|
|
- const nickName = (user.nickName || "").toLowerCase();
|
|
|
- const deptName = (user.deptName || "").toLowerCase();
|
|
|
- return userName.includes(keyword) || nickName.includes(keyword) || deptName.includes(keyword);
|
|
|
- });
|
|
|
+function searchPickerUsers() {
|
|
|
+ userPage.pageNum = 1;
|
|
|
+ loadUserList();
|
|
|
+}
|
|
|
+
|
|
|
+function closeUserPicker() {
|
|
|
+ ++userRequestVersion;
|
|
|
+ ++deptRequestVersion;
|
|
|
+ selectedUser.value = null;
|
|
|
+ userPickerLoading.value = false;
|
|
|
}
|
|
|
|
|
|
function handleUserCurrentChange(row) {
|
|
|
@@ -890,7 +902,7 @@ function openReviewerPicker() {
|
|
|
}
|
|
|
|
|
|
function confirmSelectUser() {
|
|
|
- if (!selectedUser.value) {
|
|
|
+ if (!selectedUser.value || userPickerLoading.value || userPickerError.value) {
|
|
|
ElMessage.warning("请选择用户");
|
|
|
return;
|
|
|
}
|
|
|
@@ -1183,6 +1195,11 @@ onMounted(async () => {
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
+.user-picker-right :deep(.pagination-container) {
|
|
|
+ padding: 12px 0 0;
|
|
|
+ margin-top: 0;
|
|
|
+}
|
|
|
+
|
|
|
.picker-title {
|
|
|
font-size: 14px;
|
|
|
font-weight: 600;
|