DataQualityModal.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. <template>
  2. <BasicModal
  3. v-bind="$attrs"
  4. @register="registerModal"
  5. @ok="handleSubmit"
  6. :title="getTitle"
  7. width="900px"
  8. :min-height="600"
  9. :max-height="1000"
  10. scrollable
  11. destroyOnClose
  12. :bodyStyle="{ padding: '20px' }"
  13. >
  14. <!-- 查看模式 -->
  15. <div class="que-container" v-if="mode === 'view'">
  16. <div class="que-status">
  17. <div>矿井状态:</div>
  18. <div>
  19. <span :class="getStatusClass(currentRecord?.mineLinkStatus)" class="status-dot">
  20. {{ getStatusText(currentRecord?.mineLinkStatus) }}
  21. </span>
  22. </div>
  23. </div>
  24. <div
  25. class="que-item"
  26. v-for="(item, index) in queList"
  27. :key="index"
  28. >
  29. <div class="que-details">
  30. <div class="que-field">
  31. <span class="que-value que-goafName">{{ item.goafName || '-' }}</span>
  32. </div>
  33. <div class="que-field">
  34. <span class="que-label">问题描述:</span>
  35. <span class="que-value">{{ item.queCon || '-' }}</span>
  36. </div>
  37. <div class="que-field time-field">
  38. <span class="que-label">时间:</span>
  39. <span class="que-value">{{ formatDate(item.startTime) || '-' }}</span>
  40. <span class="time-separator">-----</span>
  41. <span class="que-value">{{ formatDate(item.endTime) || '-' }}</span>
  42. </div>
  43. <div class="que-field">
  44. <span class="que-label">参数:</span>
  45. <span class="que-value">{{ (item.param || '-').replace(/,/g, ' ') }}</span>
  46. </div>
  47. </div>
  48. </div>
  49. </div>
  50. <!-- 编辑/新增模式 -->
  51. <div v-else class="edit-container">
  52. <!-- 动态渲染topFormSchema字段(编辑/新增模式) -->
  53. <div class="mine-base-info">
  54. <div class="form-item" v-for="schema in topFormSchema" :key="schema.field">
  55. <div class="form-label">{{ schema.label }}:</div>
  56. <component
  57. :is="getComponent(schema.component)"
  58. v-model:value="currentRecord[schema.field]"
  59. :disabled="mode === 'edit' && schema.field === 'mineName'"
  60. v-bind="schema.componentProps"
  61. :placeholder="`请输入${schema.label}`"
  62. style="width: 100%"
  63. />
  64. </div>
  65. </div>
  66. <!-- 问题项编辑区 -->
  67. <div
  68. class="que-item"
  69. v-for="(item, index) in queList"
  70. :key="item.orderNum || index"
  71. >
  72. <div class="que-index">问题 {{ index + 1 }}</div>
  73. <div class="edit-fields">
  74. <template v-for="schema in formSchema" :key="schema.field">
  75. <div class="form-item">
  76. <div class="form-label">{{ schema.label }}:</div>
  77. <component
  78. :is="getComponent(schema.component)"
  79. v-model:value="item[schema.field]"
  80. v-bind="schema.componentProps"
  81. :placeholder="`请输入${schema.label}`"
  82. style="width: 100%"
  83. />
  84. </div>
  85. </template>
  86. <div class="form-actions">
  87. <a-button
  88. type="text"
  89. danger
  90. @click="removeItem(index)"
  91. :disabled="queList.length <= 1"
  92. >
  93. 删除
  94. </a-button>
  95. </div>
  96. </div>
  97. </div>
  98. <a-button
  99. type="dashed"
  100. class="add-btn"
  101. @click="addNewItem"
  102. >
  103. <plus-outlined /> 新增问题
  104. </a-button>
  105. </div>
  106. </BasicModal>
  107. </template>
  108. <script setup lang="ts">
  109. import { ref, computed, unref } from 'vue';
  110. import { BasicModal, useModalInner } from '/@/components/Modal';
  111. import { formSchema, topFormSchema } from '../dataQuality.data';
  112. import { Button as AButton, Select } from 'ant-design-vue';
  113. import { Input } from 'ant-design-vue';
  114. import { DatePicker } from 'ant-design-vue';
  115. import { PlusOutlined } from '@ant-design/icons-vue';
  116. import dayjs, { Dayjs } from 'dayjs'; // 引入dayjs处理日期
  117. // 组件映射 - 增加Select组件支持
  118. const componentMap = {
  119. Input,
  120. DatePicker,
  121. Select
  122. };
  123. const emit = defineEmits(['success', 'register']);
  124. // 模式区分:view/edit/add
  125. const mode = ref<'view' | 'edit' | 'add'>('view');
  126. const currentRecord = ref<any>({
  127. mineLinkStatus: '',
  128. queJson: [],
  129. });
  130. const queList = ref<any[]>([]);
  131. // 获取组件
  132. const getComponent = (componentName: string) => {
  133. return componentMap[componentName as keyof typeof componentMap];
  134. };
  135. // 格式化日期为字符串(用于查看模式)
  136. const formatDate = (date: string | Dayjs | null) => {
  137. if (!date) return '';
  138. return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
  139. };
  140. /**
  141. * 根据状态值获取显示文本
  142. * @param status 状态值(1/0,支持字符串或数字类型)
  143. */
  144. const getStatusText = (status: string | number) => {
  145. return status === '1' || status === 1 ? '在线' : '离线';
  146. };
  147. /**
  148. * 根据状态值获取样式类
  149. * @param status 状态值(1/0,支持字符串或数字类型)
  150. */
  151. const getStatusClass = (status: string | number) => {
  152. return status === '1' || status === 1 ? 'status-online' : 'status-offline';
  153. };
  154. // 初始化弹框数据
  155. const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
  156. setModalProps({ confirmLoading: false });
  157. // 接收模式参数(view/edit/add)
  158. mode.value = data?.mode || 'view';
  159. currentRecord.value = data?.record ? { ...data.record } : {
  160. mineName: '',
  161. mineLinkStatus: '0',
  162. queJson: [],
  163. };
  164. // 初始化问题列表
  165. if (mode.value === 'add') {
  166. // 新增模式:空表单
  167. queList.value = [{
  168. orderNum: '1',
  169. goafName: '',
  170. queCon: '',
  171. startTime: null,
  172. endTime: null,
  173. param: '',
  174. }];
  175. } else {
  176. // 编辑/查看模式:使用传入数据或默认数据
  177. const rawData = currentRecord.value?.queJson
  178. ? JSON.parse(currentRecord.value.queJson)
  179. : [];
  180. console.log(rawData);
  181. // 转换日期格式:字符串 -> dayjs对象(供DatePicker使用)
  182. queList.value = rawData.map((item: any) => ({
  183. ...item,
  184. startTime: item.startTime ? dayjs(item.startTime) : null,
  185. endTime: item.endTime ? dayjs(item.endTime) : null,
  186. }));
  187. }
  188. });
  189. // 弹框标题
  190. const getTitle = computed(() => {
  191. const titles = {
  192. view: '质量问题详情',
  193. edit: '编辑质量问题',
  194. add: '新增质量问题',
  195. };
  196. return titles[mode.value];
  197. });
  198. // 新增问题
  199. const addNewItem = () => {
  200. const newItem = {
  201. orderNum: (queList.value.length + 1).toString(),
  202. goafName: '',
  203. queCon: '',
  204. startTime: null,
  205. endTime: null,
  206. param: '',
  207. };
  208. queList.value.push(newItem);
  209. };
  210. // 删除问题
  211. const removeItem = (index: number) => {
  212. queList.value.splice(index, 1);
  213. queList.value.forEach((item, i) => {
  214. item.orderNum = (i + 1).toString();
  215. });
  216. };
  217. // 提交处理
  218. async function handleSubmit() {
  219. try {
  220. setModalProps({ confirmLoading: true });
  221. // 转换日期为字符串
  222. const submitData = queList.value.map((item) => ({
  223. ...item,
  224. startTime: item.startTime ? item.startTime.format('YYYY-MM-DD HH:mm:ss') : '',
  225. endTime: item.endTime ? item.endTime.format('YYYY-MM-DD HH:mm:ss') : '',
  226. }));
  227. // 构造完整提交数据
  228. const result = {
  229. ...currentRecord.value,
  230. queJson: JSON.stringify(submitData),
  231. // 新增模式自动设置为未解决
  232. isOk: mode.value === 'add' ? false : currentRecord.value.isOk,
  233. createTime: mode.value === 'add' ? dayjs().format('YYYY-MM-DD HH:mm:ss') : '',
  234. // 当前时间作为更新时间
  235. updateTime: mode.value === 'add' ? dayjs().format('YYYY-MM-DD HH:mm:ss') : currentRecord.value.handleTime,
  236. };
  237. emit('success', result);
  238. closeModal();
  239. } finally {
  240. setModalProps({ confirmLoading: false });
  241. }
  242. }
  243. </script>
  244. <style scoped>
  245. /* 样式部分保持不变 */
  246. .que-container {
  247. display: flex;
  248. flex-direction: column;
  249. gap: 16px;
  250. }
  251. .que-status {
  252. display: flex;
  253. width: 100%;
  254. background-color: #f8f9fc;
  255. padding: 8px 16px;
  256. align-items: center;
  257. border: 1px solid #cad2e0;
  258. border-radius: 5px;
  259. }
  260. .mine-info {
  261. padding: 12px 16px;
  262. border: 1px solid #cad2e0;
  263. border-radius: 5px;
  264. background-color: #f8f9fc;
  265. }
  266. .mine-field {
  267. display: flex;
  268. align-items: center;
  269. gap: 8px;
  270. margin-bottom: 8px;
  271. }
  272. .status-dot {
  273. position: relative;
  274. padding-left: 12px;
  275. font-weight: 500;
  276. }
  277. .status-dot::before {
  278. content: '';
  279. position: absolute;
  280. left: 0;
  281. top: 50%;
  282. transform: translateY(-50%);
  283. width: 6px;
  284. height: 6px;
  285. border-radius: 50%;
  286. background-color: inherit;
  287. }
  288. .status-online {
  289. color: #10952c;
  290. font-weight: 500;
  291. }
  292. .status-offline {
  293. color: #f5222d;
  294. font-weight: 500;
  295. }
  296. .status-online.status-dot::before {
  297. background-color: #10952c;
  298. }
  299. .status-offline.status-dot::before {
  300. background-color: #f5222d;
  301. }
  302. .que-item {
  303. padding: 8px 16px;
  304. border: 1px solid #cad2e0;
  305. border-radius: 8px;
  306. background-color: #f8f9fc;
  307. }
  308. .que-index {
  309. font-size: 16px;
  310. font-weight: 600;
  311. color: #1890ff;
  312. margin-bottom: 12px;
  313. padding-bottom: 8px;
  314. border-bottom: 1px dashed #e8e8e8;
  315. }
  316. .que-details {
  317. }
  318. .que-field {
  319. display: flex;
  320. align-items: center;
  321. gap: 8px;
  322. min-width: 200px;
  323. margin-bottom: 10px;
  324. }
  325. .que-label {
  326. font-size: 16px;
  327. color: #868789;
  328. white-space: nowrap;
  329. }
  330. .que-value {
  331. font-size: 16px;
  332. color: #838486;
  333. word-break: break-all;
  334. }
  335. .que-goafName {
  336. color: #4c4c4e;
  337. font-size: 20px;
  338. }
  339. .time-field {
  340. flex: 1;
  341. min-width: 420px;
  342. }
  343. .time-separator {
  344. color: #999;
  345. margin: 0 8px;
  346. }
  347. .edit-container {
  348. display: flex;
  349. flex-direction: column;
  350. gap: 16px;
  351. }
  352. .mine-base-info {
  353. padding: 12px 16px;
  354. border: 1px solid #cad2e0;
  355. border-radius: 5px;
  356. background-color: #f8f9fc;
  357. }
  358. .edit-fields {
  359. }
  360. .form-item {
  361. display: flex;
  362. margin-bottom: 10px;
  363. align-items: center;
  364. }
  365. .form-label {
  366. width: 20%;
  367. color: #666;
  368. font-size: 14px;
  369. }
  370. .add-btn {
  371. margin-top: 8px;
  372. width: 100%;
  373. }
  374. .form-actions {
  375. display: flex;
  376. justify-content: end;
  377. margin-bottom: 8px;
  378. }
  379. </style>