approach.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  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_device_approach_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 :props="menusProps" :datas="menus" :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. <HcTooltip keys="tentative_device_approach_add">
  24. <el-button type="primary" hc-btn @click="addFormModalClick">
  25. <HcIcon name="add-circle"/>
  26. <span>新增</span>
  27. </el-button>
  28. </HcTooltip>
  29. <HcTooltip keys="tentative_device_approach_edit">
  30. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="editFormModalClick">
  31. <HcIcon name="edit"/>
  32. <span>编辑</span>
  33. </el-button>
  34. </HcTooltip>
  35. <HcTooltip keys="tentative_device_approach_del">
  36. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="delTableModalClick">
  37. <HcIcon name="delete-bin-2"/>
  38. <span>删除</span>
  39. </el-button>
  40. </HcTooltip>
  41. <HcTooltip keys="tentative_device_approach_printer">
  42. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" :loading="printerLoading" @click="printerClick">
  43. <HcIcon name="printer"/>
  44. <span>打印</span>
  45. </el-button>
  46. </HcTooltip>
  47. <HcTooltip keys="tentative_device_approach_import">
  48. <el-button hc-btn @click="importModalClick">
  49. <HcIcon name="folder-upload"/>
  50. <span>导入</span>
  51. </el-button>
  52. </HcTooltip>
  53. </template>
  54. <template #search>
  55. <div class="w-32">
  56. <el-select v-model="searchForm.isCalibration" placeholder="是否需要效验" clearable>
  57. <el-option label="是" :value="1"/>
  58. <el-option label="否" :value="0"/>
  59. </el-select>
  60. </div>
  61. <div class="w-32 ml-2">
  62. <el-select v-model="searchForm.status" placeholder="状态" clearable>
  63. <el-option label="启用中" :value="1"/>
  64. <el-option label="已停用" :value="0"/>
  65. </el-select>
  66. </div>
  67. <div class="w-64 ml-2">
  68. <HcDatePicker :dates="betweenTime" clearable @change="betweenTimeUpdate"/>
  69. </div>
  70. <div class="w-72 ml-2">
  71. <el-input v-model="searchForm.queryValue" placeholder="请输入设备名称\设备型号查询" clearable @keyup="keyUpEvent"/>
  72. </div>
  73. <div class="ml-2">
  74. <el-button type="primary" @click="searchClick">
  75. <HcIcon name="search-2"/>
  76. <span>搜索</span>
  77. </el-button>
  78. </div>
  79. </template>
  80. <HcTable ref="tableRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" isCheck @selection-change="tableSelection">
  81. <template #status="{row}">
  82. {{row.status === 1?'启用中':'已停用'}}
  83. </template>
  84. <template #isCalibration="{row}">
  85. {{row.isCalibration === 1?'是':'否'}}
  86. </template>
  87. </HcTable>
  88. <template #action>
  89. <HcPages :pages="searchForm" @change="pageChange"/>
  90. </template>
  91. </HcCard>
  92. </div>
  93. <!--新增/编辑 节点-->
  94. <HcDialog :show="addEditNodeFormModal" :title="`${addEditNodeFormModel.id?'编辑':'新增'}分类`" widths="30rem" :loading="addEditNodeFormLoading" @save="addEditNodeFormModalSave" @close="addEditNodeFormModalClose">
  95. <el-form ref="addEditNodeFormRef" :model="addEditNodeFormModel" :rules="addEditNodeFormRules" label-width="auto" label-position="top" size="large">
  96. <el-form-item class="mb-0" label="分类名称" prop="className">
  97. <el-input v-model="addEditNodeFormModel.className" placeholder="请输入分类名称"/>
  98. </el-form-item>
  99. </el-form>
  100. </HcDialog>
  101. <!--新增/编辑-->
  102. <HcDialog :show="addEditFormModal" :title="`${addEditFormModel.id?'编辑':'新增'}设备信息`" widths="50rem" :loading="addEditFormLoading" @close="addEditFormModalClose" @save="addEditFormClick">
  103. <el-form ref="addEditFormRef" :model="addEditFormModel" :rules="addEditFormRules" label-width="auto" size="large">
  104. <div class="hc-form-item">
  105. <el-form-item label="设备名称" prop="deviceName">
  106. <el-input v-model="addEditFormModel.deviceName"/>
  107. </el-form-item>
  108. <el-form-item label="进场日期">
  109. <el-date-picker type="date" v-model="addEditFormModel.mobilizationDate" class="block" value-format="YYYY-MM-DD" :clearable="false"/>
  110. </el-form-item>
  111. </div>
  112. <div class="hc-form-item">
  113. <el-form-item label="设备分类" prop="deviceClassId">
  114. <el-select v-model="addEditFormModel.deviceClassId" block>
  115. <el-option v-for="item in typeData" :label="item.className" :value="item.id"/>
  116. </el-select>
  117. </el-form-item>
  118. <el-form-item label="测量范围">
  119. <el-input v-model="addEditFormModel.measuringRange"/>
  120. </el-form-item>
  121. </div>
  122. <div class="hc-form-item">
  123. <el-form-item label="设备编号">
  124. <el-input v-model="addEditFormModel.deviceNumber"/>
  125. </el-form-item>
  126. <el-form-item label="精准度">
  127. <el-input v-model="addEditFormModel.accuracy"/>
  128. </el-form-item>
  129. </div>
  130. <div class="hc-form-item">
  131. <el-form-item label="设备型号">
  132. <el-input v-model="addEditFormModel.deviceModel"/>
  133. </el-form-item>
  134. <el-form-item label="效验周期">
  135. <HcCounter v-model="addEditFormModel.calibrationCycle" text="(月)" size="large" block/>
  136. </el-form-item>
  137. </div>
  138. <div class="hc-form-item">
  139. <el-form-item label="生产厂家">
  140. <el-input v-model="addEditFormModel.manufacturer"/>
  141. </el-form-item>
  142. <el-form-item label="最近效验时间">
  143. <el-date-picker type="date" v-model="addEditFormModel.lastCalibrationTime" class="block" value-format="YYYY-MM-DD" :clearable="false"/>
  144. </el-form-item>
  145. </div>
  146. <div class="hc-form-item">
  147. <el-form-item label="出厂日期">
  148. <el-date-picker type="date" v-model="addEditFormModel.factoryDate" class="block" value-format="YYYY-MM-DD" :clearable="false"/>
  149. </el-form-item>
  150. <el-form-item label="状态">
  151. <el-select v-model="addEditFormModel.status" placeholder="状态" block>
  152. <el-option label="启用中" :value="1"/>
  153. <el-option label="已停用" :value="0"/>
  154. </el-select>
  155. </el-form-item>
  156. </div>
  157. <div class="hc-form-item">
  158. <el-form-item label="出厂编号">
  159. <el-input v-model="addEditFormModel.factoryNumber"/>
  160. </el-form-item>
  161. <el-form-item label="管理人员">
  162. <hcAutoComplete v-model="addEditFormModel.managerName" :datas="userListData" keys="userName" placeholder="请选择或输入试验人员名称"/>
  163. </el-form-item>
  164. </div>
  165. <div class="hc-form-item">
  166. <el-form-item label="设备采集编号">
  167. <el-input v-model="addEditFormModel.equipmentAcquisitionNumber"/>
  168. </el-form-item>
  169. <el-form-item label="是否需要效验">
  170. <el-select v-model="addEditFormModel.isCalibration" block disabled>
  171. <el-option label="是" :value="1"/>
  172. <el-option label="否" :value="0"/>
  173. </el-select>
  174. </el-form-item>
  175. </div>
  176. <el-form-item label="备注">
  177. <el-input v-model="addEditFormModel.remarks" type="textarea" placeholder="备注" :autosize="{ minRows: 3}"/>
  178. </el-form-item>
  179. </el-form>
  180. </HcDialog>
  181. <!--导入-->
  182. <HcDialog :show="importModal" title="导入设备数据" widths="70rem" isTable isFooterCenter :loading="importModalLoading" @save="importModalYesClick" @close="importModalClose">
  183. <div class="text-orange mb-6">
  184. <span>请先下载模板模板表格 (</span>
  185. <span class="text-link">范例试验设备文件</span>
  186. <span>) ,按模板样式编辑试验容器后,在点击“选择文件”按钮选择编辑好的文件,点击确认即可导入成功!</span>
  187. </div>
  188. <HcDragUpload/>
  189. <div class="hc-import-modal-table-box">
  190. <HcTable ref="tableImportRef" :column="tableColumn" :datas="tableImportData" :loading="tableImportLoading" isCheck @selection-change="tableImportSelection"/>
  191. </div>
  192. </HcDialog>
  193. </div>
  194. </template>
  195. <script setup>
  196. import {ref, onMounted, watch} from "vue";
  197. import {useAppStore} from "~src/store";
  198. import {HcIsButton} from "~src/plugins/IsButtons";
  199. import HcDragUpload from "./components/HcDragUpload.vue"
  200. import approachApi from "~api/tentative/device/approach";
  201. import {formValidate, getArrValue} from "vue-utils-plus"
  202. import {getContractUserList} from "~api/other";
  203. //初始变量
  204. const useAppState = useAppStore()
  205. const projectId = ref(useAppState.getProjectId);
  206. const contractId = ref(useAppState.getContractId);
  207. const isCollapse = ref(useAppState.getCollapse)
  208. //监听
  209. watch(() => [
  210. useAppState.getCollapse
  211. ], ([Collapse]) => {
  212. isCollapse.value = Collapse
  213. })
  214. //渲染完成
  215. onMounted(() => {
  216. getClassListData()
  217. setContextMenu()
  218. getTableData()
  219. getUserListData()
  220. })
  221. //获取用户列表
  222. const userListData = ref([])
  223. const getUserListData = async () => {
  224. const { data } = await getContractUserList({
  225. contractId: contractId.value
  226. })
  227. userListData.value = getArrValue(data)
  228. }
  229. //左侧菜单
  230. const menuKey = ref('0')
  231. const menuItem = ref({})
  232. const menusProps = ref({
  233. key: 'id',
  234. label: 'className'
  235. })
  236. //获取菜单数据
  237. const menus = ref([]);
  238. const typeData = ref([]);
  239. const getClassListData = async () => {
  240. const { data } = await approachApi.getClassList({
  241. contractId: contractId.value
  242. })
  243. const arr = getArrValue(data)
  244. typeData.value = arr
  245. menus.value = [{id: '0', className: '全部', isNoContextMenu: true}, ...arr]
  246. }
  247. //菜单被点击
  248. const menuChange = (item) => {
  249. menuItem.value = item
  250. menuKey.value = item?.id
  251. searchForm.value.deviceClassId = item?.id
  252. searchForm.value.current = 1;
  253. getTableData()
  254. }
  255. //菜单的右键菜单
  256. const contextMenu = ref([])
  257. const setContextMenu = () => {
  258. let newArr = [];
  259. if (HcIsButton('tentative_device_approach_menu_edit')) {
  260. newArr.push({icon: 'draft', label: '编辑分类', key: "edit"})
  261. }
  262. if (HcIsButton('tentative_device_approach_menu_del')) {
  263. newArr.push({icon: 'delete-bin', label: '删除分类', key: "del"})
  264. }
  265. contextMenu.value = newArr
  266. }
  267. //菜单的右键菜单被点击
  268. const contextMenuClick = ({key, item}) => {
  269. if (key === 'edit') {
  270. addEditNodeFormModel.value = item
  271. addEditNodeFormModal.value = true
  272. } else if (key === 'del') {
  273. delNodeModalClick(item.id)
  274. }
  275. }
  276. //搜索表单
  277. const searchForm = ref({
  278. deviceClassId: '', isCalibration: null, status: null, startTime: null, endTime: null, queryValue: null,
  279. current: 1, size: 20, total: 0
  280. })
  281. //日期时间被选择
  282. const betweenTime = ref(null)
  283. const betweenTimeUpdate = ({arr}) => {
  284. betweenTime.value = arr
  285. if (arr.length > 0) {
  286. searchForm.value.startTime = arr[0]
  287. searchForm.value.endTime = arr[1]
  288. }
  289. }
  290. //回车搜索
  291. const keyUpEvent = (e) => {
  292. if (e.key === "Enter") {
  293. searchForm.value.current = 1;
  294. getTableData()
  295. }
  296. }
  297. //搜索
  298. const searchClick = () => {
  299. searchForm.value.current = 1;
  300. getTableData()
  301. }
  302. //分页被点击
  303. const pageChange = ({current, size}) => {
  304. searchForm.value.current = current
  305. searchForm.value.size = size
  306. getTableData()
  307. }
  308. //表格数据
  309. const tableRef = ref(null)
  310. const tableColumn = ref([
  311. {key:'deviceName', name: '设备名称', width: '200'},
  312. {key:'deviceClassName', name: '设备分类', width: '160'},
  313. {key:'deviceNumber', name: '设备编号', width: '160'},
  314. {key:'deviceModel', name: '设备型号', width: '180'},
  315. {key:'manufacturer', name: '生产厂家', width: '200'},
  316. {key:'factoryDate', name: '出厂日期', width: '160'},
  317. {key:'factoryNumber', name: '出厂编号', width: '160'},
  318. {key:'mobilizationDate', name: '进场日期', width: '160'},
  319. {key:'measuringRange', name: '测量范围', width: '120'},
  320. {key:'accuracy', name: '精准度', width: '120'},
  321. {key:'calibrationCycle', name: '校准周期(月)', width: '120'},
  322. {key:'lastCalibrationTime', name: '最近效验时间', width: '160'},
  323. {key:'status', name: '状态', width: '100'},
  324. {key:'isCalibration', name: '是否需要效验', width: '120'},
  325. {key:'equipmentAcquisitionNumber', name: '设备采集编号', width: '160'},
  326. {key:'managerName', name: '设备管理人员', width: '120'},
  327. {key:'remarks', name: '备注', width: '160'},
  328. ])
  329. const tableData = ref([])
  330. //获取数据
  331. const tableLoading = ref(false)
  332. const getTableData = async () => {
  333. tableLoading.value = true
  334. const { error, code, data } = await approachApi.queryPage({
  335. projectId: projectId.value,
  336. contractId: contractId.value,
  337. ...searchForm.value,
  338. })
  339. //处理数据
  340. tableLoading.value = false
  341. if (!error && code === 200) {
  342. tableData.value = getArrValue(data['records'])
  343. searchForm.value.total = data.total || 0
  344. } else {
  345. tableData.value = []
  346. searchForm.value.total = 0
  347. }
  348. }
  349. //多选
  350. const tableCheckedKeys = ref([]);
  351. const tableSelection = (rows) => {
  352. tableCheckedKeys.value = rows.filter((item) => {
  353. return (item??'') !== '';
  354. })
  355. }
  356. //新增/编辑 分类
  357. const addEditNodeFormRef = ref(null)
  358. const addEditNodeFormModal = ref(false)
  359. //分类表单
  360. const addEditNodeFormModel = ref({
  361. className: ''
  362. })
  363. const addEditNodeFormRules = {
  364. className: {
  365. required: true,
  366. trigger: 'blur',
  367. message: "请输入分类名称"
  368. },
  369. }
  370. //新增分类弹窗打开
  371. const addEditNodeFormModalClick = () => {
  372. addEditNodeFormModel.value = {}
  373. addEditNodeFormModal.value = true
  374. }
  375. //保存节点信息
  376. const addEditNodeFormLoading = ref(false)
  377. const addEditNodeFormModalSave = async () => {
  378. const validate = await formValidate(addEditNodeFormRef.value)
  379. if (validate) {
  380. addEditNodeFormLoading.value = true
  381. const { error, code } = await approachApi.getClassSubmit({
  382. ...addEditNodeFormModel.value,
  383. projectId: projectId.value,
  384. contractId: contractId.value
  385. })
  386. //处理数据
  387. addEditNodeFormLoading.value = false
  388. if (!error && code === 200) {
  389. window?.$message?.success('操作成功')
  390. addEditNodeFormModal.value = false
  391. await getClassListData()
  392. }
  393. }
  394. }
  395. //关闭分类编辑弹窗
  396. const addEditNodeFormModalClose = () => {
  397. addEditNodeFormModel.value = {}
  398. addEditNodeFormModal.value = false
  399. }
  400. //删除分类
  401. const delNodeModalClick = (id) => {
  402. window?.$messageBox?.alert('请谨慎考虑后,确认是否需要删除?', '删除提醒', {
  403. showCancelButton: true,
  404. confirmButtonText: '确认删除',
  405. cancelButtonText: '取消',
  406. type: 'warning',
  407. callback: (action) => {
  408. if (action === 'confirm') {
  409. setClassRemove(id)
  410. }
  411. }
  412. })
  413. }
  414. //删除分类
  415. const setClassRemove = async (id) => {
  416. const { error, code } = await approachApi.setClassRemove({
  417. projectId: projectId.value,
  418. contractId: contractId.value,
  419. id: id
  420. })
  421. //处理数据
  422. if (!error && code === 200) {
  423. window?.$message?.success('操作成功')
  424. await getClassListData()
  425. }
  426. }
  427. //删除表格数据
  428. const delTableModalClick = () => {
  429. window?.$messageBox?.alert('请谨慎考虑后,确认是否需要删除?', '删除提醒', {
  430. showCancelButton: true,
  431. confirmButtonText: '确认删除',
  432. cancelButtonText: '取消',
  433. type: 'warning',
  434. callback: (action) => {
  435. if (action === 'confirm') {
  436. tableRemoveData()
  437. }
  438. }
  439. })
  440. }
  441. //批量删除
  442. const tableRemoveData = async () => {
  443. const rows = tableCheckedKeys.value
  444. if (rows.length > 0 ) {
  445. const ids = rowsToId(rows)
  446. //删除请求
  447. const { error, code } = await approachApi.removeData({
  448. contractId: contractId.value,
  449. ids: ids,
  450. })
  451. //处理数据
  452. if (!error && code === 200) {
  453. window?.$message?.success('操作成功')
  454. searchClick()
  455. }
  456. }
  457. }
  458. //打印
  459. const printerLoading = ref(false)
  460. const printerClick = async () => {
  461. const rows = tableCheckedKeys.value
  462. if (rows.length > 0 ) {
  463. printerLoading.value = true
  464. const ids = rowsToId(rows)
  465. //删除请求
  466. const { error, code, data } = await approachApi.exportPdf({
  467. projectId: projectId.value,
  468. contractId: contractId.value,
  469. ids: ids,
  470. })
  471. //处理数据
  472. printerLoading.value = false
  473. if (!error && code === 200) {
  474. window.open(data,'_blank')
  475. }
  476. }
  477. }
  478. //导入
  479. const importModal = ref(false)
  480. const importModalClick = () => {
  481. importModal.value = true
  482. }
  483. //确认导入
  484. const importModalLoading = ref(false)
  485. const importModalYesClick = () => {
  486. importModal.value = false
  487. }
  488. //关闭导入
  489. const importModalClose = () => {
  490. importModal.value = false
  491. }
  492. //表格数据
  493. const tableImportRef = ref(null)
  494. const tableImportLoading = ref(false)
  495. const tableImportData = ref([])
  496. //多选
  497. const tableImportKeys = ref([]);
  498. const tableImportSelection = (rows) => {
  499. tableImportKeys.value = rows.filter((item) => {
  500. return (item??'') !== '';
  501. })
  502. }
  503. //新增/编辑 表单
  504. const addEditFormRef = ref(null)
  505. const addEditFormModel = ref({})
  506. const addEditFormRules = {
  507. deviceName: {
  508. required: true,
  509. trigger: 'blur',
  510. message: "请输入设备名称"
  511. },
  512. deviceClassId: {
  513. required: true,
  514. trigger: 'blur',
  515. message: "请选择设备分类"
  516. },
  517. }
  518. //新增 设备信息
  519. const addEditFormModal = ref(false)
  520. const addFormModalClick = () => {
  521. addEditFormModel.value = {
  522. isCalibration: 0,
  523. status: 1,
  524. }
  525. addEditFormModal.value = true
  526. }
  527. //编辑 设备信息
  528. const editFormModalClick = () => {
  529. const keys = tableCheckedKeys.value
  530. if (keys.length === 1) {
  531. addEditFormModel.value = keys[0]
  532. addEditFormModal.value = true
  533. } else if (keys.length > 1) {
  534. window?.$message?.warning('只能选择一条数据编辑')
  535. }
  536. }
  537. //关闭新增/编辑的弹窗
  538. const addEditFormModalClose = () => {
  539. addEditFormModal.value = false
  540. addEditFormModel.value = {
  541. isCalibration: 0,
  542. status: 1
  543. }
  544. }
  545. //新增/编辑 保存
  546. const addEditFormLoading = ref(false)
  547. const addEditFormClick = async () => {
  548. const validate = await formValidate(addEditFormRef.value)
  549. if (validate) {
  550. addEditFormLoading.value = true
  551. const { error, code } = await approachApi.submitForm({
  552. ...addEditFormModel.value,
  553. projectId: projectId.value,
  554. contractId: contractId.value
  555. })
  556. //处理数据
  557. addEditFormLoading.value = false
  558. if (!error && code === 200) {
  559. window?.$message?.success('操作成功')
  560. addEditFormModal.value = false
  561. await getTableData()
  562. }
  563. }
  564. }
  565. //拼接ID
  566. const rowsToId = (rows) => {
  567. return rows.map((obj) => {
  568. return obj.id;
  569. }).join(",")
  570. }
  571. //左右拖动,改变树形结构宽度
  572. const leftWidth = ref(240);
  573. const onmousedown = () => {
  574. const leftNum = isCollapse.value ? 142 : 272
  575. document.onmousemove = (ve) => {
  576. let diffVal = ve.clientX - leftNum;
  577. if(diffVal >= 220 && diffVal <= 400) {
  578. leftWidth.value = diffVal;
  579. }
  580. }
  581. document.onmouseup = () => {
  582. document.onmousemove = null;
  583. document.onmouseup = null;
  584. }
  585. }
  586. </script>
  587. <style lang="scss" scoped>
  588. .hc-import-modal-table-box {
  589. position: relative;
  590. height: calc(100% - 228px);
  591. margin-top: 25px;
  592. }
  593. </style>