|
|
@@ -0,0 +1,405 @@
|
|
|
+<template>
|
|
|
+ <BasicModal
|
|
|
+ v-bind="$attrs"
|
|
|
+ @register="registerModal"
|
|
|
+ @ok="handleSubmit"
|
|
|
+ :title="getTitle"
|
|
|
+ width="900px"
|
|
|
+ :min-height="600"
|
|
|
+ :max-height="1000"
|
|
|
+ scrollable
|
|
|
+ destroyOnClose
|
|
|
+ :bodyStyle="{ padding: '20px' }"
|
|
|
+ >
|
|
|
+ <!-- 查看模式 -->
|
|
|
+ <div class="que-container" v-if="mode === 'view'">
|
|
|
+ <div class="que-status">
|
|
|
+ <div>矿井状态:</div>
|
|
|
+ <div>
|
|
|
+ <span :class="getStatusClass(currentRecord?.mineLinkStatus || mockFormdData.mineLinkStatus)" class="status-dot">
|
|
|
+ {{ getStatusText(currentRecord?.mineLinkStatus || mockFormdData.mineLinkStatus) }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 动态渲染topFormSchema字段(查看模式) -->
|
|
|
+ <div class="mine-info">
|
|
|
+ <div class="mine-field" v-for="schema in topFormSchema" :key="schema.field">
|
|
|
+ <span class="que-label">{{ schema.label }}:</span>
|
|
|
+ <span class="que-value">{{ currentRecord?.[schema.field] || mockFormdData[schema.field] }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="que-item"
|
|
|
+ v-for="(item, index) in queList"
|
|
|
+ :key="index"
|
|
|
+ >
|
|
|
+ <div class="que-details">
|
|
|
+ <div class="que-field">
|
|
|
+ <span class="que-value que-goafName">{{ item.goafName || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="que-field">
|
|
|
+ <span class="que-label">问题描述:</span>
|
|
|
+ <span class="que-value">{{ item.queCon || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="que-field time-field">
|
|
|
+ <span class="que-label">时间:</span>
|
|
|
+ <span class="que-value">{{ formatDate(item.startTime) || '-' }}</span>
|
|
|
+ <span class="time-separator">-----</span>
|
|
|
+ <span class="que-value">{{ formatDate(item.endTime) || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="que-field">
|
|
|
+ <span class="que-label">参数:</span>
|
|
|
+ <span class="que-value">{{ (item.param || '-').replace(/,/g, ' ') }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 编辑/新增模式 -->
|
|
|
+ <div v-else class="edit-container">
|
|
|
+ <!-- 动态渲染topFormSchema字段(编辑/新增模式) -->
|
|
|
+ <div class="mine-base-info">
|
|
|
+ <div class="form-item" v-for="schema in topFormSchema" :key="schema.field">
|
|
|
+ <div class="form-label">{{ schema.label }}:</div>
|
|
|
+ <component
|
|
|
+ :is="getComponent(schema.component)"
|
|
|
+ v-model:value="currentRecord[schema.field]"
|
|
|
+ :disabled="mode === 'edit' && schema.field === 'mineName'"
|
|
|
+ v-bind="schema.componentProps"
|
|
|
+ :placeholder="`请输入${schema.label}`"
|
|
|
+ style="width: 100%"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 问题项编辑区 -->
|
|
|
+ <div
|
|
|
+ class="que-item"
|
|
|
+ v-for="(item, index) in queList"
|
|
|
+ :key="item.orderNum || index"
|
|
|
+ >
|
|
|
+ <div class="que-index">问题 {{ index + 1 }}</div>
|
|
|
+ <div class="edit-fields">
|
|
|
+ <template v-for="schema in formSchema" :key="schema.field">
|
|
|
+ <div class="form-item">
|
|
|
+ <div class="form-label">{{ schema.label }}:</div>
|
|
|
+ <component
|
|
|
+ :is="getComponent(schema.component)"
|
|
|
+ v-model:value="item[schema.field]"
|
|
|
+ v-bind="schema.componentProps"
|
|
|
+ :placeholder="`请输入${schema.label}`"
|
|
|
+ style="width: 100%"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="form-actions">
|
|
|
+ <a-button
|
|
|
+ type="text"
|
|
|
+ danger
|
|
|
+ @click="removeItem(index)"
|
|
|
+ :disabled="queList.length <= 1"
|
|
|
+ >
|
|
|
+ 删除
|
|
|
+ </a-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <a-button
|
|
|
+ type="dashed"
|
|
|
+ class="add-btn"
|
|
|
+ @click="addNewItem"
|
|
|
+ >
|
|
|
+ <plus-outlined /> 新增问题
|
|
|
+ </a-button>
|
|
|
+ </div>
|
|
|
+ </BasicModal>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, computed, unref } from 'vue';
|
|
|
+import { BasicModal, useModalInner } from '/@/components/Modal';
|
|
|
+import { mockFormdData, formSchema, topFormSchema } from '../dataQuality.data';
|
|
|
+import { Button as AButton, Select } from 'ant-design-vue';
|
|
|
+import { Input } from 'ant-design-vue';
|
|
|
+import { DatePicker } from 'ant-design-vue';
|
|
|
+import { PlusOutlined } from '@ant-design/icons-vue';
|
|
|
+import dayjs, { Dayjs } from 'dayjs'; // 引入dayjs处理日期
|
|
|
+
|
|
|
+// 组件映射 - 增加Select组件支持
|
|
|
+const componentMap = {
|
|
|
+ Input,
|
|
|
+ DatePicker,
|
|
|
+ Select
|
|
|
+};
|
|
|
+
|
|
|
+const emit = defineEmits(['success', 'register']);
|
|
|
+
|
|
|
+// 模式区分:view/edit/add
|
|
|
+const mode = ref<'view' | 'edit' | 'add'>('view');
|
|
|
+const currentRecord = ref<any>({
|
|
|
+ mineLinkStatus: '',
|
|
|
+ queJson: [],
|
|
|
+});
|
|
|
+const queList = ref<any[]>([]);
|
|
|
+
|
|
|
+// 获取组件
|
|
|
+const getComponent = (componentName: string) => {
|
|
|
+ return componentMap[componentName as keyof typeof componentMap];
|
|
|
+};
|
|
|
+
|
|
|
+// 格式化日期为字符串(用于查看模式)
|
|
|
+const formatDate = (date: string | Dayjs | null) => {
|
|
|
+ if (!date) return '';
|
|
|
+ return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 根据状态值获取显示文本
|
|
|
+ * @param status 状态值(1/0,支持字符串或数字类型)
|
|
|
+ */
|
|
|
+const getStatusText = (status: string | number) => {
|
|
|
+ return status === '1' || status === 1 ? '在线' : '离线';
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 根据状态值获取样式类
|
|
|
+ * @param status 状态值(1/0,支持字符串或数字类型)
|
|
|
+ */
|
|
|
+const getStatusClass = (status: string | number) => {
|
|
|
+ return status === '1' || status === 1 ? 'status-online' : 'status-offline';
|
|
|
+};
|
|
|
+
|
|
|
+// 初始化弹框数据
|
|
|
+const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
|
|
+ setModalProps({ confirmLoading: false });
|
|
|
+
|
|
|
+ // 接收模式参数(view/edit/add)
|
|
|
+ mode.value = data?.mode || 'view';
|
|
|
+ currentRecord.value = data?.record ? { ...data.record } : {
|
|
|
+ mineName: '',
|
|
|
+ mineLinkStatus: '0',
|
|
|
+ queJson: [],
|
|
|
+ };
|
|
|
+
|
|
|
+ // 初始化问题列表
|
|
|
+ if (mode.value === 'add') {
|
|
|
+ // 新增模式:空表单
|
|
|
+ queList.value = [{
|
|
|
+ orderNum: '1',
|
|
|
+ goafName: '',
|
|
|
+ queCon: '',
|
|
|
+ startTime: null,
|
|
|
+ endTime: null,
|
|
|
+ param: '',
|
|
|
+ }];
|
|
|
+ } else {
|
|
|
+ // 编辑/查看模式:使用传入数据或默认数据
|
|
|
+ const rawData = currentRecord.value?.queJson
|
|
|
+ ? JSON.parse(JSON.stringify(currentRecord.value.queJson))
|
|
|
+ : JSON.parse(JSON.stringify(mockFormdData.queJson));
|
|
|
+
|
|
|
+ // 转换日期格式:字符串 -> dayjs对象(供DatePicker使用)
|
|
|
+ queList.value = rawData.map((item: any) => ({
|
|
|
+ ...item,
|
|
|
+ startTime: item.startTime ? dayjs(item.startTime) : null,
|
|
|
+ endTime: item.endTime ? dayjs(item.endTime) : null,
|
|
|
+ }));
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 弹框标题
|
|
|
+const getTitle = computed(() => {
|
|
|
+ const titles = {
|
|
|
+ view: '质量问题详情',
|
|
|
+ edit: '编辑质量问题',
|
|
|
+ add: '新增质量问题',
|
|
|
+ };
|
|
|
+ return titles[mode.value];
|
|
|
+});
|
|
|
+
|
|
|
+// 新增问题
|
|
|
+const addNewItem = () => {
|
|
|
+ const newItem = {
|
|
|
+ orderNum: (queList.value.length + 1).toString(),
|
|
|
+ goafName: '',
|
|
|
+ queCon: '',
|
|
|
+ startTime: null,
|
|
|
+ endTime: null,
|
|
|
+ param: '',
|
|
|
+ };
|
|
|
+ queList.value.push(newItem);
|
|
|
+};
|
|
|
+
|
|
|
+// 删除问题
|
|
|
+const removeItem = (index: number) => {
|
|
|
+ queList.value.splice(index, 1);
|
|
|
+ queList.value.forEach((item, i) => {
|
|
|
+ item.orderNum = (i + 1).toString();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 提交处理
|
|
|
+async function handleSubmit() {
|
|
|
+ try {
|
|
|
+ setModalProps({ confirmLoading: true });
|
|
|
+ // 转换日期为字符串
|
|
|
+ const submitData = queList.value.map((item) => ({
|
|
|
+ ...item,
|
|
|
+ startTime: item.startTime ? item.startTime.format('YYYY-MM-DD HH:mm:ss') : '',
|
|
|
+ endTime: item.endTime ? item.endTime.format('YYYY-MM-DD HH:mm:ss') : '',
|
|
|
+ }));
|
|
|
+ // 构造完整提交数据
|
|
|
+ const result = {
|
|
|
+ ...currentRecord.value,
|
|
|
+ queJson: submitData,
|
|
|
+ // 新增模式自动设置为未解决
|
|
|
+ isOk: mode.value === 'add' ? '未解决' : currentRecord.value.isOk,
|
|
|
+ // 新增时补充当前时间作为处理时间
|
|
|
+ handleTime: mode.value === 'add' ? dayjs().format('YYYY-MM-DD HH:mm:ss') : currentRecord.value.handleTime,
|
|
|
+ };
|
|
|
+ emit('success', result);
|
|
|
+ closeModal();
|
|
|
+ } finally {
|
|
|
+ setModalProps({ confirmLoading: false });
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+/* 样式部分保持不变 */
|
|
|
+.que-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+.que-status {
|
|
|
+ display: flex;
|
|
|
+ width: 100%;
|
|
|
+ background-color: #f8f9fc;
|
|
|
+ padding: 8px 16px;
|
|
|
+ align-items: center;
|
|
|
+ border: 1px solid #cad2e0;
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+.mine-info {
|
|
|
+ padding: 12px 16px;
|
|
|
+ border: 1px solid #cad2e0;
|
|
|
+ border-radius: 5px;
|
|
|
+ background-color: #f8f9fc;
|
|
|
+}
|
|
|
+.mine-field {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+.status-dot {
|
|
|
+ position: relative;
|
|
|
+ padding-left: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+.status-dot::before {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ width: 6px;
|
|
|
+ height: 6px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background-color: inherit;
|
|
|
+}
|
|
|
+.status-online {
|
|
|
+ color: #10952c;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+.status-offline {
|
|
|
+ color: #f5222d;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+.status-online.status-dot::before {
|
|
|
+ background-color: #10952c;
|
|
|
+}
|
|
|
+.status-offline.status-dot::before {
|
|
|
+ background-color: #f5222d;
|
|
|
+}
|
|
|
+.que-item {
|
|
|
+ padding: 8px 16px;
|
|
|
+ border: 1px solid #cad2e0;
|
|
|
+ border-radius: 8px;
|
|
|
+ background-color: #f8f9fc;
|
|
|
+}
|
|
|
+.que-index {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1890ff;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ padding-bottom: 8px;
|
|
|
+ border-bottom: 1px dashed #e8e8e8;
|
|
|
+}
|
|
|
+.que-details {
|
|
|
+}
|
|
|
+.que-field {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ min-width: 200px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+.que-label {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #868789;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.que-value {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #838486;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+.que-goafName {
|
|
|
+ color: #4c4c4e;
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+.time-field {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 420px;
|
|
|
+}
|
|
|
+.time-separator {
|
|
|
+ color: #999;
|
|
|
+ margin: 0 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.edit-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+.mine-base-info {
|
|
|
+ padding: 12px 16px;
|
|
|
+ border: 1px solid #cad2e0;
|
|
|
+ border-radius: 5px;
|
|
|
+ background-color: #f8f9fc;
|
|
|
+}
|
|
|
+.edit-fields {
|
|
|
+}
|
|
|
+.form-item {
|
|
|
+ display: flex;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.form-label {
|
|
|
+ width: 20%;
|
|
|
+ color: #666;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+.add-btn {
|
|
|
+ margin-top: 8px;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.form-actions {
|
|
|
+ display: flex;
|
|
|
+ justify-content: end;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+</style>
|