container.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. <template>
  2. <div class="hc-page-layout-box">
  3. <div class="hc-layout-left-box menu" :style="'width:' + leftWidth + 'px;'">
  4. <div class="hc-menu-header-box">
  5. <div class="text-xl name">试验容器</div>
  6. <HcTooltip keys="tentative_parameter_container_menu_add">
  7. <el-button type="primary" hc-btn _icon size="small" @click="addEditNodeFormModalClick">
  8. <HcIcon name="add"/>
  9. </el-button>
  10. </HcTooltip>
  11. </div>
  12. <div class="hc-menu-contents-box">
  13. <el-scrollbar>
  14. <HcMenuSimple :datas="menus" :props="menuProps" :keys="menuKey" :menus="contextMenu" @change="menuChange" @menuTap="contextMenuClick"/>
  15. </el-scrollbar>
  16. </div>
  17. <!--左右拖动-->
  18. <div class="horizontal-drag-line" @mousedown="onmousedown"/>
  19. </div>
  20. <div class="hc-page-content-box">
  21. <HcCard>
  22. <template #header>
  23. <div class="w-72">
  24. <el-input v-model="searchForm.queryValue" placeholder="请输入容器编号查询" clearable @keyup="keyUpEvent" size="large"/>
  25. </div>
  26. <div class="ml-2">
  27. <el-button type="primary" @click="searchClick" size="large">
  28. <HcIcon name="search-2"/>
  29. <span>搜索</span>
  30. </el-button>
  31. </div>
  32. </template>
  33. <template #extra>
  34. <HcTooltip keys="tentative_parameter_container_add">
  35. <el-button type="primary" hc-btn @click="addFormModalClick">
  36. <HcIcon name="add-circle"/>
  37. <span>新增</span>
  38. </el-button>
  39. </HcTooltip>
  40. <HcTooltip keys="tentative_parameter_container_edit">
  41. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="editFormModalClick">
  42. <HcIcon name="edit"/>
  43. <span>编辑</span>
  44. </el-button>
  45. </HcTooltip>
  46. <HcTooltip keys="tentative_parameter_container_del">
  47. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="delTableModalClick">
  48. <HcIcon name="delete-bin-2"/>
  49. <span>删除</span>
  50. </el-button>
  51. </HcTooltip>
  52. <HcTooltip keys="tentative_parameter_container_printer">
  53. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0">
  54. <HcIcon name="printer"/>
  55. <span>打印</span>
  56. </el-button>
  57. </HcTooltip>
  58. <HcTooltip keys="tentative_parameter_container_import">
  59. <el-button hc-btn @click="importModalClick">
  60. <HcIcon name="folder-upload"/>
  61. <span>导入</span>
  62. </el-button>
  63. </HcTooltip>
  64. </template>
  65. <HcTable ref="tableRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" isCheck @selection-change="tableSelection"/>
  66. <template #action>
  67. <HcPages :pages="searchForm" @change="pageChange"/>
  68. </template>
  69. </HcCard>
  70. </div>
  71. <!--新增/编辑 节点-->
  72. <HcDialog :show="addEditNodeFormModal" :title="`${addEditNodeFormModel.id?'编辑':'新增'}试验容器`" widths="30rem" isRowFooter @close="addEditNodeFormModalClose">
  73. <el-form :model="addEditNodeFormModel" label-width="auto" label-position="top" size="large">
  74. <el-form-item label="试验容器名称">
  75. <el-input v-model="addEditNodeFormModel.containerName" placeholder="请输入试验容器名称"/>
  76. </el-form-item>
  77. <template v-for="(item, index) in addEditNodeFormModel.fieldList">
  78. <div class="hc-form-item">
  79. <el-form-item class="w-32" label="数据类型" style="flex: initial;">
  80. <el-select v-model="item.fieldType" block>
  81. <el-option label="文本" :value="1"/>
  82. <el-option label="日期框" :value="2"/>
  83. </el-select>
  84. </el-form-item>
  85. <el-form-item label="字段名">
  86. <template #label>
  87. <div class="solt-label">
  88. <span class="mr-1">字段名</span>
  89. <span class="text-xs text-slate-400" v-if="index === 0">第一个作为编号,是唯一的</span>
  90. </div>
  91. <div class="solt-extra">
  92. <el-button type="primary" plain size="small" @click="addEditNodeDataDel(item,index)">删除</el-button>
  93. </div>
  94. </template>
  95. <el-input v-model="item.fieldName" block/>
  96. </el-form-item>
  97. </div>
  98. </template>
  99. </el-form>
  100. <template #leftRowFooter>
  101. <el-button size="large" @click="addEditNodeDataAdd">
  102. <HcIcon name="add"/>
  103. <span>加字段</span>
  104. </el-button>
  105. </template>
  106. <template #rightRowFooter>
  107. <el-button size="large" @click="addEditNodeFormModalClose">
  108. <HcIcon name="close"/>
  109. <span>取消</span>
  110. </el-button>
  111. <el-button type="primary" hc-btn :loading="addEditNodeFormLoading" @click="addEditNodeFormModalSave">
  112. <HcIcon name="check"/>
  113. <span>提交</span>
  114. </el-button>
  115. </template>
  116. </HcDialog>
  117. <!--新增/编辑-->
  118. <HcDialog :show="addEditFormModal" :title="`${addEditFormModel.id?'编辑':'新增'}数据`" widths="30rem" :loading="addEditFormLoading" @close="addEditFormModalClose" @save="addEditFormClick">
  119. <el-form ref="addEditFormRef" :model="addEditFormModel" :rules="addEditFormRules" label-width="auto" size="large">
  120. <template v-for="(item, index) in tableColumn">
  121. <el-form-item :label="item.name" :prop="item.key">
  122. <el-input v-model="addEditFormModel[item.key]" :placeholder="`${index===0?'作为编号,是唯一的':'请输入' + item.name}`" v-if="item.type === 1"/>
  123. <el-date-picker type="date" v-model="addEditFormModel[item.key]" class="block" value-format="YYYY-MM-DD" :clearable="false" v-if="item.type === 2"/>
  124. </el-form-item>
  125. </template>
  126. </el-form>
  127. </HcDialog>
  128. <!--导入-->
  129. <HcDialog :show="importModal" title="导入" widths="38rem" isRowFooter @close="importModalClose">
  130. <HcDragUpload/>
  131. <template #leftRowFooter>
  132. <el-button size="large">
  133. <HcIcon name="download-2"/>
  134. <span>下载模板</span>
  135. </el-button>
  136. </template>
  137. <template #rightRowFooter>
  138. <el-button size="large" @click="importModalClose">
  139. <HcIcon name="close"/>
  140. <span>取消导入</span>
  141. </el-button>
  142. <el-button type="primary" hc-btn :loading="importModalLoading" @click="importModalYesClick">
  143. <HcIcon name="folder-upload"/>
  144. <span>确认导入</span>
  145. </el-button>
  146. </template>
  147. </HcDialog>
  148. </div>
  149. </template>
  150. <script setup>
  151. import {ref, onMounted, watch} from "vue";
  152. import {useAppStore} from "~src/store";
  153. import {HcIsButton} from "~src/plugins/IsButtons";
  154. import {formValidate, getArrValue} from "vue-utils-plus"
  155. import HcDragUpload from "./components/HcDragUpload.vue"
  156. import dataApi from "~api/tentative/parameter/container"
  157. //初始变量
  158. const useAppState = useAppStore()
  159. const projectId = ref(useAppState.getProjectId);
  160. const contractId = ref(useAppState.getContractId);
  161. const isCollapse = ref(useAppState.getCollapse)
  162. //监听
  163. watch(() => [
  164. useAppState.getCollapse
  165. ], ([Collapse]) => {
  166. isCollapse.value = Collapse
  167. })
  168. //渲染完成
  169. onMounted(() => {
  170. getMenusData()
  171. setContextMenu()
  172. })
  173. //左侧菜单
  174. const menuProps = {
  175. key: 'id',
  176. label: 'containerName',
  177. }
  178. const menus = ref([]);
  179. const getMenusData = async () => {
  180. const { data } = await dataApi.queryClassification({
  181. projectId: projectId.value,
  182. contractId: contractId.value
  183. })
  184. const arr = getArrValue(data)
  185. menus.value = arr
  186. if (arr.length > 0) {
  187. const item = arr[0]
  188. menuItem.value = item
  189. menuKey.value = item?.id
  190. setMenuTableColumn(item?.fieldList)
  191. }
  192. }
  193. //菜单被点击
  194. const menuKey = ref('')
  195. const menuItem = ref({})
  196. const menuChange = (item) => {
  197. menuItem.value = item
  198. menuKey.value = item?.id
  199. setMenuTableColumn(item?.fieldList)
  200. }
  201. //设置表格头
  202. const setMenuTableColumn = (data) => {
  203. let newArr = [];
  204. for (let i = 0; i < data.length; i++) {
  205. newArr.push({
  206. key: data[i].fieldKey,
  207. name: data[i].fieldName,
  208. type: data[i].fieldType
  209. })
  210. }
  211. newArr.push({
  212. key: 'field_calibration_time',
  213. name: '校准日期',
  214. type: 2
  215. })
  216. tableColumn.value = newArr
  217. //取列表数据
  218. searchClick()
  219. setAddEditFormRules(newArr)
  220. }
  221. //菜单的右键菜单
  222. const contextMenu = ref([])
  223. const setContextMenu = () => {
  224. let newArr = [];
  225. if (HcIsButton('tentative_parameter_container_menu_edit')) {
  226. newArr.push({icon: 'draft', label: '编辑容器', key: "edit"})
  227. }
  228. if (HcIsButton('tentative_parameter_container_menu_del')) {
  229. newArr.push({icon: 'delete-bin', label: '删除容器', key: "del"})
  230. }
  231. contextMenu.value = newArr
  232. }
  233. //菜单的右键菜单被点击
  234. const contextMenuClick = ({key, item}) => {
  235. if (key === 'edit') {
  236. addEditNodeFormModel.value = item
  237. addEditNodeFormModal.value = true
  238. } else if (key === 'del') {
  239. delNodeModalClick(item.id)
  240. }
  241. }
  242. //搜索表单
  243. const searchForm = ref({
  244. queryValue: null, current: 1, size: 20, total: 0
  245. })
  246. //日期时间被选择
  247. const betweenTime = ref(null)
  248. const betweenTimeUpdate = ({arr,query}) => {
  249. betweenTime.value = arr
  250. searchForm.value.betweenTime = query
  251. }
  252. //回车搜索
  253. const keyUpEvent = (e) => {
  254. if (e.key === "Enter") {
  255. searchForm.value.current = 1;
  256. getTableData()
  257. }
  258. }
  259. //搜索
  260. const searchClick = () => {
  261. searchForm.value.current = 1;
  262. getTableData()
  263. }
  264. //分页被点击
  265. const pageChange = ({current, size}) => {
  266. searchForm.value.current = current
  267. searchForm.value.size = size
  268. getTableData()
  269. }
  270. //表格数据
  271. const tableRef = ref(null)
  272. const tableColumn = ref([])
  273. const tableData = ref([])
  274. //获取数据
  275. const tableLoading = ref(false)
  276. const getTableData = async () => {
  277. const {id, fieldList} = menuItem.value
  278. const fieldLists = getArrValue(fieldList)
  279. if (fieldLists.length > 0) {
  280. tableLoading.value = true
  281. const { error, code, data } = await dataApi.queryPage({
  282. projectId: projectId.value,
  283. contractId: contractId.value,
  284. ...searchForm.value,
  285. fieldKey: fieldList[0].fieldKey,
  286. id: id
  287. })
  288. //处理数据
  289. tableLoading.value = false
  290. if (!error && code === 200) {
  291. tableData.value = getArrValue(data['records'])
  292. searchForm.value.total = data.total || 0
  293. } else {
  294. tableData.value = []
  295. searchForm.value.total = 0
  296. }
  297. } else {
  298. window.$message.warning('请先设置容器字段')
  299. }
  300. }
  301. //多选
  302. const tableCheckedKeys = ref([]);
  303. const tableSelection = (rows) => {
  304. tableCheckedKeys.value = rows
  305. }
  306. //新增/编辑 分类
  307. const addEditNodeFormModal = ref(false)
  308. const addEditNodeFormModel = ref({
  309. containerName: '', fieldList: [{
  310. fieldType: 1,
  311. fieldName: ''
  312. }]
  313. })
  314. const addEditNodeFormModalClick = () => {
  315. addEditNodeFormModel.value = {
  316. containerName: '', fieldList: [{
  317. fieldType: 1,
  318. fieldName: ''
  319. }]
  320. }
  321. addEditNodeFormModal.value = true
  322. }
  323. //加字段
  324. const addEditNodeDataAdd = () => {
  325. addEditNodeFormModel.value.fieldList.push({
  326. fieldType: 1,
  327. fieldName: ''
  328. })
  329. }
  330. //删除当前行
  331. const addEditNodeDataDel = async ({fieldId}, index) => {
  332. if (!fieldId) {
  333. addEditNodeFormModel.value.fieldList.splice(index, 1);
  334. } else {
  335. const { error, code } = await dataApi.removeField({fieldId})
  336. if (!error && code === 200) {
  337. addEditNodeFormModel.value.fieldList.splice(index, 1);
  338. }
  339. }
  340. }
  341. //保存节点信息
  342. const addEditNodeFormLoading = ref(false)
  343. const addEditNodeFormModalSave = () => {
  344. const form = addEditNodeFormModel.value
  345. if (!form.containerName) {
  346. window.$message.warning('请输入容器名称')
  347. } else if (form.fieldList.length <= 0) {
  348. window.$message.warning('请添加容器字段')
  349. } else {
  350. //判断是否满足条件
  351. const result = form.fieldList.every(({fieldName})=> {
  352. return fieldName !== ''
  353. })
  354. if (!result) {
  355. window.$message.warning('请先完善字段数据')
  356. } else {
  357. form.projectId = projectId.value
  358. form.contractId = contractId.value
  359. submitClassification(form)
  360. }
  361. }
  362. }
  363. //提交保存分类
  364. const submitClassification = async (form) => {
  365. addEditNodeFormLoading.value = true
  366. const { error, code } = await dataApi.submitClassification(form)
  367. //处理数据
  368. addEditNodeFormLoading.value = false
  369. if (!error && code === 200) {
  370. window?.$message?.success('操作成功')
  371. addEditNodeFormModal.value = false
  372. await getMenusData()
  373. }
  374. }
  375. //关闭分类编辑弹窗
  376. const addEditNodeFormModalClose = () => {
  377. addEditNodeFormModal.value = false
  378. }
  379. //删除分类
  380. const delNodeModalClick = (id) => {
  381. window?.$messageBox?.alert('请谨慎考虑后,确认是否需要删除?', '删除提醒', {
  382. showCancelButton: true,
  383. confirmButtonText: '确认删除',
  384. cancelButtonText: '取消',
  385. type: 'warning',
  386. callback: (action) => {
  387. if (action === 'confirm') {
  388. removeClassification(id)
  389. }
  390. }
  391. })
  392. }
  393. //删除容器
  394. const removeClassification = async (id) => {
  395. //删除请求
  396. const { error, code } = await dataApi.removeClassification({
  397. projectId: projectId.value,
  398. contractId: contractId.value,
  399. id: id,
  400. })
  401. //处理数据
  402. if (!error && code === 200) {
  403. window?.$message?.success('操作成功')
  404. getMenusData()
  405. }
  406. }
  407. //新增/编辑 表单
  408. const addEditFormRef = ref(null)
  409. const addEditFormModel = ref({})
  410. const addEditFormRules = ref({})
  411. //处理表单校验
  412. const setAddEditFormRules = (fieldList) => {
  413. let newArr = {};
  414. for (let i = 0; i < fieldList.length; i++) {
  415. const item = fieldList[i];
  416. if (i === 0) {
  417. newArr[item.key] = {
  418. required: true,
  419. validator: async (rule, value, callback) => {
  420. if (!value) {
  421. callback(new Error("请输入" + item.name))
  422. } else {
  423. const ver = await verification(item.key, value)
  424. if (!ver) {
  425. callback(new Error(item.name + '必须是惟一的'))
  426. } else {
  427. callback()
  428. }
  429. }
  430. },
  431. trigger: 'blur'
  432. }
  433. } else if (item.type === 1) {
  434. newArr[item.key] = {
  435. required: true,
  436. trigger: 'blur',
  437. message: "请输入" + item.name
  438. }
  439. } else if (item.type === 2) {
  440. newArr[item.key] = {
  441. required: true,
  442. trigger: 'blur',
  443. message: "请选择" + item.name
  444. }
  445. }
  446. }
  447. addEditFormRules.value = newArr
  448. }
  449. //校验材料编号是否唯一
  450. const verification = async (key, val) => {
  451. const { containerInitTabName } = menuItem.value
  452. const { error, code, data } = await dataApi.verification({
  453. projectId: projectId.value,
  454. contractId: contractId.value,
  455. bean: {
  456. fieldKey: key,
  457. fieldValue: val
  458. },
  459. containerInitTabName: containerInitTabName
  460. })
  461. if (!error && code === 200) {
  462. return data === '编号可以使用';
  463. } else {
  464. return false
  465. }
  466. }
  467. //新增/编辑
  468. const addEditFormModal = ref(false)
  469. const addFormModalClick = () => {
  470. addEditFormModel.value = {}
  471. addEditFormModal.value = true
  472. }
  473. //编辑表单
  474. const editFormModalClick = () => {
  475. const keys = tableCheckedKeys.value
  476. if (keys.length === 1) {
  477. addEditFormModel.value = keys[0]
  478. addEditFormModal.value = true
  479. } else if (keys.length > 1) {
  480. window?.$message?.warning('只能选择一条数据编辑')
  481. }
  482. }
  483. //关闭表单
  484. const addEditFormModalClose = () => {
  485. addEditFormModal.value = false
  486. }
  487. //新增/编辑 保存
  488. const addEditFormLoading = ref(false)
  489. const addEditFormClick = async () => {
  490. const validate = await formValidate(addEditFormRef.value)
  491. if (validate) {
  492. const { containerInitTabName } = menuItem.value
  493. const form = addEditFormModel.value
  494. addEditFormLoading.value = true
  495. //处理数据格式
  496. let beanList = [];
  497. Object.keys(form).forEach(key => {
  498. if (key !== 'field_calibration_time') {
  499. beanList.push({
  500. fieldKey: key,
  501. fieldValue: form[key]
  502. })
  503. }
  504. })
  505. //发起请求
  506. const { error, code } = await dataApi.submitForm({
  507. projectId: projectId.value,
  508. contractId: contractId.value,
  509. beanList,
  510. containerInitTabName,
  511. fieldCalibrationTime: form['field_calibration_time'],
  512. id: form['id'] ?? ''
  513. })
  514. //处理数据
  515. addEditFormLoading.value = false
  516. if (!error && code === 200) {
  517. window?.$message?.success('操作成功')
  518. addEditFormModal.value = false
  519. await getTableData()
  520. }
  521. }
  522. }
  523. //删除数据
  524. const delTableModalClick = () => {
  525. window?.$messageBox?.alert('请谨慎考虑后,确认是否需要删除?', '删除提醒', {
  526. showCancelButton: true,
  527. confirmButtonText: '确认删除',
  528. cancelButtonText: '取消',
  529. type: 'warning',
  530. callback: (action) => {
  531. if (action === 'confirm') {
  532. tableRemoveData()
  533. }
  534. }
  535. })
  536. }
  537. //批量删除
  538. const tableRemoveData = async () => {
  539. const rows = tableCheckedKeys.value
  540. if (rows.length > 0 ) {
  541. const ids = rowsToId(rows)
  542. const { containerInitTabName } = menuItem.value
  543. //删除请求
  544. const { error, code } = await dataApi.removeData({
  545. projectId: projectId.value,
  546. contractId: contractId.value,
  547. containerInitTabName: containerInitTabName,
  548. ids: ids,
  549. })
  550. //处理数据
  551. if (!error && code === 200) {
  552. window?.$message?.success('操作成功')
  553. searchClick()
  554. }
  555. }
  556. }
  557. //导入
  558. const importModal = ref(false)
  559. const importModalClick = () => {
  560. importModal.value = true
  561. }
  562. //确认导入
  563. const importModalLoading = ref(false)
  564. const importModalYesClick = () => {
  565. importModal.value = false
  566. }
  567. //关闭导入
  568. const importModalClose = () => {
  569. importModal.value = false
  570. }
  571. //拼接ID
  572. const rowsToId = (rows) => {
  573. return rows.map((obj) => {
  574. return obj.id;
  575. }).join(",")
  576. }
  577. //左右拖动,改变树形结构宽度
  578. const leftWidth = ref(240);
  579. const onmousedown = () => {
  580. const leftNum = isCollapse.value ? 142 : 272
  581. document.onmousemove = (ve) => {
  582. let diffVal = ve.clientX - leftNum;
  583. if(diffVal >= 220 && diffVal <= 400) {
  584. leftWidth.value = diffVal;
  585. }
  586. }
  587. document.onmouseup = () => {
  588. document.onmousemove = null;
  589. document.onmouseup = null;
  590. }
  591. }
  592. </script>
  593. <style lang="scss" scoped>
  594. .hc-import-modal-table-box {
  595. position: relative;
  596. height: calc(100% - 228px);
  597. margin-top: 25px;
  598. }
  599. </style>