sampling.vue 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131
  1. <template>
  2. <hc-body split :project-nmae="projectInfo?.projectName">
  3. <template #tree>
  4. <TestTree
  5. :auto-expand-keys="treeAutoExpandKeys" :project-id="projectId" :tenant-id="userInfo?.tenant_id"
  6. :wbs-temp-id="projectInfo?.referenceWbsTemplateIdTrial" :wbs-type="2" :entrust="1"
  7. @node-tap="wbsElTreeClick"
  8. />
  9. </template>
  10. <hc-new-card w-to="1919">
  11. <template #headerToSearch>
  12. <div class="w-50">
  13. <el-select v-model="searchForm.contractId" placeholder="选择合同段" filterable block>
  14. <el-option v-for="item in contractData" :key="item.id" :label="item.contractName" :value="item.id" />
  15. </el-select>
  16. </div>
  17. <div class="ml-2 w-250px">
  18. <hc-date-picker :dates="betweenTime" clearable @change="betweenTimeUpdate" />
  19. </div>
  20. <div class="ml-2 w-72">
  21. <el-input v-model="searchForm.queryValue" clearable placeholder="请输入名称、规格、样品编号查询" @keyup="keyUpEvent" />
  22. </div>
  23. <div class="ml-2">
  24. <el-button type="primary" @click="searchClick">
  25. <hc-icon name="search-2" />
  26. <span>搜索</span>
  27. </el-button>
  28. </div>
  29. </template>
  30. <template #extraToHeader>
  31. <hc-tooltip keys="tentative_material_sampling_add">
  32. <el-button :disabled="!primaryKeyId" hc-btn type="primary" @click="addFormModalClick">
  33. <hc-icon name="add-circle" />
  34. <span>新增</span>
  35. </el-button>
  36. </hc-tooltip>
  37. <hc-tooltip keys="tentative_material_sampling_edit">
  38. <el-button :disabled="tableCheckedKeys.length <= 0" hc-btn type="primary" color="#12C060" style="color: white;" @click="editFormModalClick">
  39. <hc-icon name="edit" />
  40. <span>编辑</span>
  41. </el-button>
  42. </hc-tooltip>
  43. <hc-tooltip keys="tentative_material_sampling_copy">
  44. <el-button :disabled="tableCheckedKeys.length <= 0" hc-btn color="#A16222" @click="copyTableModalClick">
  45. <hc-icon name="file-copy-2" />
  46. <span>复制</span>
  47. </el-button>
  48. </hc-tooltip>
  49. <hc-tooltip keys="tentative_material_sampling_del">
  50. <el-button v-del-com:[delModalClick] :disabled="tableCheckedKeys.length <= 0" hc-btn color="#e03997">
  51. <hc-icon name="delete-bin-2" />
  52. <span>删除</span>
  53. </el-button>
  54. </hc-tooltip>
  55. <!-- <hc-tooltip keys="tentative_material_sampling_printer">
  56. <el-button :disabled="tableCheckedKeys.length <= 0" :loading="printerLoading" hc-btn color="#567722" @click="printerClick">
  57. <hc-icon name="printer" />
  58. <span>打印</span>
  59. </el-button>
  60. </hc-tooltip>
  61. <hc-tooltip keys="tentative_material_sampling_import">
  62. <el-button :disabled="!primaryKeyId" hc-btn color="#567722" @click="importModalClick">
  63. <hc-icon name="folder-upload" />
  64. <span>导入</span>
  65. </el-button>
  66. </hc-tooltip> -->
  67. <hc-tooltip keys="tentative_material_sampling_delegation">
  68. <el-button hc-btn color="#E75643" :disabled="!nodeErTreeId" @click="delegationClick">
  69. <hc-icon name="slack" />
  70. <span>委托</span>
  71. </el-button>
  72. </hc-tooltip>
  73. </template>
  74. <hc-table
  75. ref="tableRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check
  76. :index-style="{ width: 60 }" :check-style="{ width: 29 }" @selection-change="tableSelection"
  77. >
  78. <template #materialCount="{ row }">{{ row.materialCount === -1 ? "" : row.materialCount }}</template>
  79. <template #representativeCount="{ row }">
  80. {{ row.representativeCount === -1 ? "" : row.representativeCount }}
  81. </template>
  82. </hc-table>
  83. <template #action>
  84. <hc-pages :pages="searchForm" @change="pageChange" />
  85. </template>
  86. </hc-new-card>
  87. <!-- 新增/编辑 -->
  88. <hc-new-dialog v-model="addEditFormModal" :title="`${addEditFormModel.id ? '编辑' : '新增'}样品信息`" is-row-footer widths="50rem" @close="addEditFormModalClose">
  89. <el-form ref="addEditFormRef" :model="addEditFormModel" :rules="addEditFormRules" label-width="auto" size="large">
  90. <div class="hc-form-item">
  91. <el-form-item label="样品名称" prop="materialName">
  92. <el-input v-model="addEditFormModel.materialName" />
  93. </el-form-item>
  94. <el-form-item label="进场日期">
  95. <el-date-picker v-model="addEditFormModel.mobilizationDate" :clearable="false" class="block" type="date" value-format="YYYY-MM-DD" />
  96. </el-form-item>
  97. </div>
  98. <div class="hc-form-item">
  99. <el-form-item label="样品编号" prop="specificationNumber">
  100. <el-input v-model="addEditFormModel.specificationNumber" />
  101. </el-form-item>
  102. <el-form-item label="取样日期">
  103. <el-date-picker v-model="addEditFormModel.samplingDate" :clearable="false" class="block" type="date" value-format="YYYY-MM-DD" />
  104. </el-form-item>
  105. </div>
  106. <div class="hc-form-item">
  107. <el-form-item label="规格型号">
  108. <el-input v-model="addEditFormModel.specificationModel" />
  109. </el-form-item>
  110. <el-form-item label="取样地点">
  111. <el-input v-model="addEditFormModel.samplingLocation" />
  112. </el-form-item>
  113. </div>
  114. <div class="hc-form-item">
  115. <el-form-item label="试样数量">
  116. <el-input v-model="addEditFormModel.materialCount" type="number" />
  117. </el-form-item>
  118. <el-form-item label="试样单位">
  119. <el-input v-model="addEditFormModel.calculationUnit" />
  120. </el-form-item>
  121. </div>
  122. <div class="hc-form-item">
  123. <el-form-item label="代表数量">
  124. <el-input v-model="addEditFormModel.representativeCount" type="number" />
  125. </el-form-item>
  126. <el-form-item label="代表单位">
  127. <el-input v-model="addEditFormModel.representativeUnit" />
  128. </el-form-item>
  129. </div>
  130. <div class="hc-form-item">
  131. <el-form-item label="设计强度">
  132. <el-input v-model="addEditFormModel.designStrength" />
  133. </el-form-item>
  134. <el-form-item label="是否外委">
  135. <el-radio-group v-model="addEditFormModel.isOutsourcing" size="large">
  136. <el-radio :value="1">是</el-radio>
  137. <el-radio :value="0">否</el-radio>
  138. </el-radio-group>
  139. </el-form-item>
  140. </div>
  141. <div class="hc-form-item">
  142. <el-form-item label="供应商">
  143. <el-input v-model="addEditFormModel.supplierUnit" />
  144. </el-form-item>
  145. <el-form-item label="生产批号">
  146. <el-input v-model="addEditFormModel.batchNumber" />
  147. </el-form-item>
  148. </div>
  149. <div class="hc-form-item">
  150. <el-form-item label="取样人">
  151. <el-select v-model="addEditFormModel.userId" block @change="changeusername">
  152. <el-option v-for="item in userListData" :key="item.userId" :label="item.userName" :value="item.userId" />
  153. </el-select>
  154. </el-form-item>
  155. <el-form-item label="拟用部位">
  156. <el-input v-model="addEditFormModel.proposedPosition" />
  157. </el-form-item>
  158. </div>
  159. <div class="hc-form-item">
  160. <el-form-item label="是否使用RFID" prop="isRfid">
  161. <el-radio-group v-model="addEditFormModel.isRfid" size="large" @change="formRfidChange">
  162. <el-radio :value="1">是</el-radio>
  163. <el-radio :value="0">否</el-radio>
  164. </el-radio-group>
  165. </el-form-item>
  166. <el-form-item v-if="addEditFormModel.isRfid === 1" label="RFID编号" prop="rfId">
  167. <el-select v-model="addEditFormModel.rfId" clearable block>
  168. <el-option v-for="item in deviceTable" :key="item.epc" :label="item.epc" :value="item.epc" />
  169. </el-select>
  170. </el-form-item>
  171. </div>
  172. <el-form-item label="样品描述">
  173. <el-input v-model="addEditFormModel.sampleDescription" />
  174. </el-form-item>
  175. </el-form>
  176. <template #leftRowFooter>
  177. <hc-tooltip keys="tentative_material_sampling_links">
  178. <el-button hc-btn type="primary" @click="linksApproachModalClick(addEditFormModel.mobilizationId)">
  179. <hc-icon name="links" />
  180. <span>关联进场材料</span>
  181. </el-button>
  182. </hc-tooltip>
  183. </template>
  184. <template #rightRowFooter>
  185. <el-button size="large" @click="addEditFormModalClose">
  186. <hc-icon name="close" />
  187. <span>取消</span>
  188. </el-button>
  189. <el-button :loading="addEditFormLoading" hc-btn type="primary" @click="addEditFormClick">
  190. <hc-icon name="check" />
  191. <span>确认</span>
  192. </el-button>
  193. </template>
  194. </hc-new-dialog>
  195. <!-- 关联进场材料 -->
  196. <hc-new-dialog v-model="linksApproachModal" is-row-footer is-table title="关联进场材料信息" widths="60%" @close="linksApproachModalClose">
  197. <hc-table :column="linksApproachTableColumn" :datas="linksApproachTableData" :is-index="false" :loading="linksApproachTableLoading">
  198. <template #materialType="{ row }">{{ getRowTableMaterialType(row.materialType) }}</template>
  199. <template #action="{ row }">
  200. <hc-tooltip keys="tentative_material_approach_annex">
  201. <el-button v-if="mobilizationId === row.id" plain size="small" type="primary" @click="cancelApproachRow(row)">取消关联</el-button>
  202. <el-button v-else plain size="small" type="primary" @click="linksApproachRow(row)">关联</el-button>
  203. </hc-tooltip>
  204. </template>
  205. </hc-table>
  206. <template #leftRowFooter>
  207. <hc-pages :pages="ApproachSearchForm" @change="linksApproachPageChange" />
  208. </template>
  209. <template #rightRowFooter>
  210. <el-button size="large" @click="linksApproachModalClose">
  211. <hc-icon name="close" />
  212. <span>取消</span>
  213. </el-button>
  214. <el-button hc-btn type="primary" @click="linksApproachModalSave">
  215. <hc-icon name="check" />
  216. <span>确定</span>
  217. </el-button>
  218. </template>
  219. </hc-new-dialog>
  220. <!-- 复制样品登记信息 -->
  221. <hc-new-dialog v-model="copyTableModal" :loading="copyTableLoading" is-table title="复制样品登记信息" widths="60rem" @close="copyTableModalClose" @save="copyTableClick">
  222. <hc-table :column="copyTableColumn" :datas="copyTableData" is-new :index-style="{ width: 60 }">
  223. <template #specificationNumber="{ row }">
  224. <el-input v-model="row.specificationNumber" placeholder="请输入样品编号" />
  225. </template>
  226. <template #action="{ index }">
  227. <el-button plain size="small" type="danger" @click="specificationNumberDel(index)">删除</el-button>
  228. </template>
  229. </hc-table>
  230. </hc-new-dialog>
  231. <!-- 导入 -->
  232. <hc-new-dialog v-model="importModal" is-row-footer title="导入" widths="38rem" @close="importModalClose">
  233. <HcDragUpload ref="uploadRef" api="/api/blade-business/material/" :datas="uploadData" action="sample/import" @finished="uploadFinished" @progress="uploadprogress" />
  234. <template #leftRowFooter>
  235. <el-button size="large" @click="downloadImportClick">
  236. <hc-icon name="download-2" />
  237. <span>下载模板</span>
  238. </el-button>
  239. </template>
  240. <template #rightRowFooter>
  241. <el-button size="large" @click="importModalClose">
  242. <hc-icon name="close" />
  243. <span>取消导入</span>
  244. </el-button>
  245. <el-button :loading="importModalLoading" hc-btn type="primary" @click="importModalYesClick">
  246. <hc-icon name="folder-upload" />
  247. <span>确认导入</span>
  248. </el-button>
  249. </template>
  250. </hc-new-dialog>
  251. <!-- 创建委托 -->
  252. <hc-new-dialog v-model="delegateModal" ui="hc-delegate-html-modal" is-table is-footer-center title="创建委托" widths="60rem" @close="delegateModalClose">
  253. <div class="hc-delegate-contract hc-flex h-40px">
  254. <el-select v-model="delegateContractId" placeholder="请先选择合同段" filterable class="w-400px" @change="delegateContractChange">
  255. <el-option v-for="item in contractData" :key="item.id" :label="item.contractName" :value="item.id" />
  256. </el-select>
  257. </div>
  258. <div class="hc-delegate-html" :class="delegateContractId ? 'is-show' : ''">
  259. <hc-table-form ref="htmlRef" :pkey="nodeErTreeId" :form="delegateHtmlForm" :html="delegateHtml" :loading="delegateHtmlLoading" @render="delegateHtmlRender" />
  260. </div>
  261. <template #footer>
  262. <el-button @click="delegateModalClose">取消</el-button>
  263. <el-button hc-btn type="primary" :loading="creatingDelegateLoading" @click="creatingDelegate">创建</el-button>
  264. </template>
  265. </hc-new-dialog>
  266. </hc-body>
  267. </template>
  268. <script setup>
  269. import { onActivated, onUnmounted, ref, watch } from 'vue'
  270. import { useAppStore } from '~src/store'
  271. import TestTree from './components/TestTree.vue'
  272. import HcDragUpload from './components/HcDragUpload.vue'
  273. import { getStoreValue, setStoreValue } from '~src/utils/storage'
  274. import commissionApi from '~api/tentative/detect/commission'
  275. import samplingApi from '~api/tentative/material/sampling'
  276. import approachApi from '~api/tentative/material/approach'
  277. import { getContractUserList, getDictionary } from '~api/other'
  278. import { arrIndex, arrToId, deepClone, formValidate, getArrValue, getObjVal, getObjValue, isNullES, isString } from 'js-fast-way'
  279. import { toPdfPage } from '~uti/btn-auth'
  280. import Dayjs from 'dayjs'
  281. import dataApi from '~api/basic/code'
  282. //变量
  283. const useAppState = useAppStore()
  284. const userInfo = ref(useAppState.getUserInfo)
  285. const projectId = ref(useAppState.getProjectId)
  286. const contractId = ref(useAppState.getContractId)
  287. const projectInfo = ref(useAppState.getProjectInfo)
  288. const isCollapse = ref(useAppState.getCollapse)
  289. //监听
  290. watch(() => useAppState.getCollapse, (collapse) => {
  291. isCollapse.value = collapse
  292. })
  293. //自动展开缓存
  294. const treeAutoExpandKeys = ref(getStoreValue('testTreeExpandKeys') || [])
  295. //渲染完成
  296. onActivated(() => {
  297. getContractData()
  298. getUserListData()
  299. getMaterialType()
  300. })
  301. //获取材料类型
  302. const typeData = ref([])
  303. const getMaterialType = async () => {
  304. const { data } = await getDictionary({
  305. code: 'material_type',
  306. })
  307. typeData.value = getArrValue(data)
  308. }
  309. //获取材料类型
  310. const getRowTableMaterialType = (type) => {
  311. if (type > 0) {
  312. const nodeData = typeData.value
  313. const index = arrIndex(nodeData, 'dictKey', type)
  314. return nodeData[index]?.dictValue ?? type
  315. } else {
  316. return ''
  317. }
  318. }
  319. //获取合同段信息
  320. const contractData = ref([])
  321. const getContractData = async () => {
  322. const { data } = await samplingApi.getErtractInfo({
  323. projectId: projectId.value,
  324. contractId: contractId.value,
  325. })
  326. const res = getArrValue(data)
  327. contractData.value = res
  328. if (res.length <= 0) return
  329. let cid
  330. for (let i = 0; i < res.length; i++) {
  331. if (contractId.value == res[i].id) {
  332. cid = res[i].id
  333. }
  334. }
  335. searchForm.value.contractId = isNullES(cid) ? res[0].id : cid
  336. searchClick()
  337. }
  338. //获取用户列表
  339. const userListData = ref([])
  340. const getUserListData = async () => {
  341. const { data } = await getContractUserList({
  342. contractId: contractId.value,
  343. })
  344. userListData.value = getArrValue(data)
  345. }
  346. //搜索表单
  347. const searchForm = ref({
  348. startTime: null, endTime: null, queryValue: null, nodeId: '',
  349. current: 1, size: 20, total: 0,
  350. })
  351. //树相关的变量
  352. const primaryKeyId = ref('')
  353. const nodeErTreeId = ref('')
  354. const nodeItemInfo = ref({})
  355. const nodeDataInfo = ref({})
  356. //树被点击
  357. const wbsElTreeClick = ({ node, data, keys }) => {
  358. nodeItemInfo.value = node
  359. nodeDataInfo.value = data
  360. primaryKeyId.value = data['primaryKeyId'] || ''
  361. nodeErTreeId.value = data['erTreeId'] || ''
  362. //缓存自动展开
  363. treeAutoExpandKeys.value = keys
  364. setStoreValue('testTreeExpandKeys', keys)
  365. //改变搜索表单数据
  366. searchForm.value.nodeId = data['primaryKeyId'] || ''
  367. searchForm.value.current = 1
  368. getTableData()
  369. }
  370. //日期时间被选择
  371. const betweenTime = ref(null)
  372. const betweenTimeUpdate = ({ arr }) => {
  373. betweenTime.value = arr
  374. if (arr.length > 0) {
  375. searchForm.value.startTime = arr[0]
  376. searchForm.value.endTime = arr[1]
  377. } else {
  378. searchForm.value.startTime = ''
  379. searchForm.value.endTime = ''
  380. }
  381. }
  382. //回车搜索
  383. const keyUpEvent = (e) => {
  384. if (e.key === 'Enter') {
  385. searchForm.value.current = 1
  386. getTableData()
  387. }
  388. }
  389. //搜索
  390. const searchClick = () => {
  391. searchForm.value.current = 1
  392. getTableData()
  393. }
  394. //分页被点击
  395. const pageChange = ({ current, size }) => {
  396. searchForm.value.current = current
  397. searchForm.value.size = size
  398. getTableData()
  399. }
  400. //表格数据
  401. const tableRef = ref(null)
  402. const tableColumn = ref([
  403. { key: 'materialName', name: '取样名称', width: 160, align: 'center' },
  404. { key: 'samplingDate', name: '取样日期', width: 120, align: 'center' },
  405. { key: 'specificationNumber', name: '样品编号', width: 470, align: 'center' },
  406. { key: 'specificationModel', name: '规格型号', width: 180, align: 'center' },
  407. { key: 'materialCount', name: '试样数量', width: 70, align: 'center' },
  408. { key: 'calculationUnit', name: '试样单位', width: 70, align: 'center' },
  409. { key: 'proposedPosition', name: '拟用部位', width: 470, align: 'center' },
  410. { key: 'representativeCount', name: '代表数量', width: 70, align: 'center' },
  411. { key: 'representativeUnit', name: '代表单位', width: 70, align: 'center' },
  412. { key: 'userName', name: '取样人', width: 70, align: 'center' },
  413. ])
  414. //获取数据
  415. const tableLoading = ref(false)
  416. const tableData = ref([])
  417. const getTableData = async () => {
  418. const nodeId = primaryKeyId.value
  419. if (isNullES(nodeId)) return
  420. tableLoading.value = true
  421. const { error, code, data } = await samplingApi.queryPage({
  422. projectId: projectId.value,
  423. nodeId,
  424. ...searchForm.value,
  425. })
  426. //处理数据
  427. tableLoading.value = false
  428. if (!error && code === 200) {
  429. tableData.value = getArrValue(data['records'])
  430. searchForm.value.total = data.total || 0
  431. } else {
  432. tableData.value = []
  433. searchForm.value.total = 0
  434. }
  435. }
  436. //多选
  437. const tableCheckedKeys = ref([])
  438. const tableSelection = (rows) => {
  439. tableCheckedKeys.value = rows
  440. }
  441. //新增
  442. const addEditFormModal = ref(false)
  443. const addFormModalClick = () => {
  444. const toDayDate = new Dayjs().format('YYYY-MM-DD')
  445. addEditFormModel.value = {
  446. isRfid: 0,
  447. isOutsourcing: 0,
  448. mobilizationId: '',
  449. mobilizationDate: toDayDate,
  450. samplingDate: toDayDate,
  451. nodeId: primaryKeyId.value,
  452. userId: userInfo.value.user_id,
  453. }
  454. addEditFormModal.value = true
  455. getMaterialNumber()
  456. // requestDevice()
  457. }
  458. //获取材料编号
  459. const backObj = ref({})
  460. const getMaterialNumber = async () => {
  461. const { error, code, data } = await dataApi.getTrialNumber({
  462. projectId: projectId.value,
  463. contractId: contractId.value,
  464. type: 2,
  465. nodeId:primaryKeyId.value,
  466. })
  467. //处理数据
  468. if (!error && code === 200) {
  469. backObj.value = getObjVal(data)
  470. addEditFormModel.value.specificationNumber = data.trialNumber
  471. } else {
  472. backObj.value = {}
  473. addEditFormModel.value.specificationNumber = ''
  474. }
  475. }
  476. //编辑
  477. const editFormModalClick = () => {
  478. const keys = tableCheckedKeys.value
  479. if (keys.length === 1) {
  480. const obj = deepClone(keys[0])
  481. addEditFormModel.value = {
  482. ...obj,
  483. representativeCount: obj.representativeCount === -1 ? '' : obj.representativeCount,
  484. materialCount: obj.materialCount === -1 ? '' : obj.materialCount,
  485. isRfid: isNullES(obj.rfId) ? 0 : 1,
  486. }
  487. addEditFormModal.value = true
  488. // requestDevice()
  489. } else if (keys.length > 1) {
  490. window?.$message?.warning('只能选择一条数据编辑')
  491. }
  492. }
  493. //获取读卡器设备
  494. let device
  495. const deviceTable = ref([])
  496. const requestDevice = async () => {
  497. if (isNullES(device)) {
  498. const devices = await navigator.hid.requestDevice({
  499. filters: [{ vendorId: 1240, productId: 831 }],
  500. })
  501. if (devices.length <= 0) return
  502. device = devices[0]
  503. }
  504. // 检查设备是否打开
  505. if (!device.opened) {
  506. await device.open() // 打开设备
  507. }
  508. // 电脑接收到来自设备的消息回调
  509. deviceTable.value = []
  510. device.oninputreport = (event) => {
  511. if (!addEditFormModal.value) return
  512. const { isRfid, rfId } = addEditFormModel.value
  513. if (isRfid !== 1 ) return
  514. const array = new Uint8Array(event.data.buffer)
  515. const data = array.slice(10, array[0] - 1)
  516. let epc = ''
  517. const res = new Uint8Array(data)
  518. for (const data of res) {
  519. // 将字节数据转换成(XX )形式字符串
  520. epc += (Array(2).join(0) + data.toString(16).toUpperCase()).slice(-2) + ''
  521. }
  522. const index = arrIndex(deviceTable.value, 'epc', epc)
  523. if (index === -1) {
  524. deviceTable.value.push({ epc: epc })
  525. }
  526. if (isNullES(rfId)) {
  527. addEditFormModel.value.rfId = epc
  528. }
  529. }
  530. }
  531. //是否使用RFID
  532. const formRfidChange = () => {
  533. const { isRfid } = addEditFormModel.value
  534. if (isRfid !== 1) {
  535. addEditFormModel.value.rfId = ''
  536. deviceTable.value = []
  537. } else {
  538. requestDevice()
  539. }
  540. }
  541. //弹窗关闭
  542. const addEditFormModalClose = async () => {
  543. addEditFormModal.value = false
  544. addEditFormModel.value = {}
  545. // 关闭设备
  546. if (!isNullES(device)) {
  547. await device.close()
  548. }
  549. }
  550. //新增/编辑 表单
  551. const addEditFormRef = ref(null)
  552. const addEditFormModel = ref({})
  553. const addEditFormRules = {
  554. materialName: {
  555. required: true,
  556. trigger: 'blur',
  557. message: '请输入样品名称',
  558. },
  559. specificationNumber: {
  560. required: false,
  561. validator: async (rule, value, callback) => {
  562. if (!value) {
  563. // callback(new Error('请输入样品编号'))
  564. } else {
  565. const ver = await verification(value)
  566. if (!ver) {
  567. callback(new Error('样品编号必须是惟一的'))
  568. } else {
  569. callback()
  570. }
  571. }
  572. },
  573. trigger: 'blur',
  574. },
  575. rfId: {
  576. required: true,
  577. validator: async (rule, value, callback) => {
  578. const { isRfid } = addEditFormModel.value
  579. if (isRfid !== 1) {
  580. callback()
  581. } else if (isNullES(value)) {
  582. callback(new Error('请选择RFID编号'))
  583. } else {
  584. callback()
  585. }
  586. },
  587. trigger: 'blur',
  588. },
  589. }
  590. //校验材料编号是否唯一
  591. const verification = async (val) => {
  592. const { error, code, data } = await samplingApi.verification({
  593. projectId: projectId.value,
  594. contractId: searchForm.value.contractId,
  595. specificationNumber: val,
  596. id: addEditFormModel.value.id ?? '',
  597. nodeId: primaryKeyId.value,
  598. })
  599. if (!error && code === 200) {
  600. return !data
  601. } else {
  602. return false
  603. }
  604. }
  605. //新增/编辑 保存
  606. const addEditFormLoading = ref(false)
  607. const addEditFormClick = async () => {
  608. const validate = await formValidate(addEditFormRef.value)
  609. if (!validate) return false
  610. addEditFormLoading.value = true
  611. const form = addEditFormModel.value
  612. if (form.isRfid !== 1 ) {
  613. form.rfId = ''
  614. }
  615. form.projectId = projectId.value
  616. form.contractId = searchForm.value.contractId
  617. form.trialNumber = backObj.value?.trialNumber
  618. form.autoIncrementNumber = backObj.value?.autoIncrementNumber
  619. const { error, code, msg } = await samplingApi.submitForm(form)
  620. //处理数据
  621. addEditFormLoading.value = false
  622. if (!error && code === 200) {
  623. window?.$message?.success('操作成功')
  624. addEditFormModalClose().then()
  625. await getTableData()
  626. } else {
  627. window?.$message?.error(msg || '操作失败')
  628. }
  629. }
  630. //复制表格
  631. const copyTableColumn = ref([
  632. { key: 'materialName', name: '样品名称' },
  633. { key: 'specificationNumber', name: '样品编号' },
  634. { key: 'action', name: '操作', width: 100 },
  635. ])
  636. const copyTableData = ref([])
  637. //复制
  638. const copyTableModal = ref(false)
  639. const copyTableModalClick = () => {
  640. copyTableModal.value = true
  641. copyTableData.value = deepClone(tableCheckedKeys.value)
  642. }
  643. //删除
  644. const specificationNumberDel = (index) => {
  645. copyTableData.value.splice(index, 1)
  646. const rows = copyTableData.value
  647. if (rows.length <= 0) {
  648. copyTableModal.value = false
  649. }
  650. }
  651. const copyTableModalClose = () => {
  652. copyTableModal.value = false
  653. }
  654. //复制 保存
  655. const copyTableLoading = ref(false)
  656. const copyTableClick = () => {
  657. copyTableModal.value = false
  658. const rows = copyTableData.value
  659. if (rows.length > 0) {
  660. for (let i = 0; i < rows.length; i++) {
  661. rows[i].dataNumber = i
  662. }
  663. tableCopyData(rows)
  664. } else {
  665. window.$message?.warning('请先在列表勾选要复制的数据')
  666. copyTableModal.value = false
  667. }
  668. }
  669. //复制数据请求
  670. const tableCopyData = async (rows) => {
  671. copyTableLoading.value = true
  672. const { error, code, msg } = await samplingApi.copyData(rows)
  673. //处理数据
  674. copyTableLoading.value = false
  675. if (!error && code === 200) {
  676. window?.$message?.success('操作成功')
  677. copyTableModal.value = false
  678. await getTableData()
  679. } else {
  680. window?.$message?.error(msg || '操作失败')
  681. }
  682. }
  683. //删除
  684. const delModalClick = async (_, resolve) => {
  685. await tableRemoveData()
  686. resolve()
  687. }
  688. //批量删除
  689. const tableRemoveData = async () => {
  690. const rows = tableCheckedKeys.value
  691. if (rows.length > 0) {
  692. const ids = arrToId(rows)
  693. //删除请求
  694. const { error, code, msg } = await samplingApi.removeData({
  695. projectId: projectId.value,
  696. contractId: searchForm.value.contractId,
  697. ids: ids,
  698. })
  699. //处理数据
  700. if (!error && code === 200) {
  701. window?.$message?.success('操作成功')
  702. searchClick()
  703. } else {
  704. window?.$message?.error(msg || '操作失败')
  705. }
  706. }
  707. }
  708. //打印
  709. const printerLoading = ref(false)
  710. const printerClick = async () => {
  711. const rows = tableCheckedKeys.value
  712. if (rows.length > 0) {
  713. printerLoading.value = true
  714. const ids = arrToId(rows)
  715. //删除请求
  716. const { error, code, data } = await samplingApi.exportPdf({
  717. projectId: projectId.value,
  718. contractId: searchForm.value.contractId,
  719. ids: ids,
  720. })
  721. //处理数据
  722. printerLoading.value = false
  723. if (!error && code === 200) {
  724. toPdfPage(data)
  725. //window.open(data, '_blank')
  726. }
  727. }
  728. }
  729. //导入
  730. const uploadRef = ref(null)
  731. const uploadData = ref({})
  732. //导入
  733. const importModal = ref(false)
  734. const importModalClick = () => {
  735. importModal.value = true
  736. uploadData.value = {
  737. contractId: searchForm.value.contractId,
  738. nodeId: primaryKeyId.value,
  739. isCovered: 1,
  740. }
  741. }
  742. //上传进度
  743. const uploadprogress = (res) => {
  744. importModalLoading.value = res
  745. }
  746. //确认导入
  747. const importModalLoading = ref(false)
  748. const importModalYesClick = () => {
  749. uploadRef.value?.submit()
  750. }
  751. //上传完成
  752. const uploadFinished = () => {
  753. importModal.value = false
  754. getTableData()
  755. }
  756. //关闭导入
  757. const importModalClose = () => {
  758. importModal.value = false
  759. }
  760. //更改取样人名称changeusername
  761. const changeusername = (item) => {
  762. userListData.value.forEach((ele) => {
  763. if (item == ele.userId) {
  764. addEditFormModel.value.userName = ele.userName
  765. }
  766. })
  767. }
  768. //关联进场材料
  769. const linksApproachModal = ref(false)
  770. const ApproachSearchForm = ref({
  771. current: 1, size: 20, total: 0,
  772. })
  773. const mobilizationId = ref('')
  774. const linksApproachModalClick = (mId) => {
  775. mobilizationId.value = mId ?? ''
  776. ApproachSearchForm.value.current = 1
  777. linksApproachModal.value = true
  778. getApproachTableData()
  779. }
  780. //分页被点击
  781. const linksApproachPageChange = ({ current, size }) => {
  782. ApproachSearchForm.value.current = current
  783. ApproachSearchForm.value.size = size
  784. getApproachTableData()
  785. }
  786. //关联进场材料数据
  787. const linksApproachTableColumn = ref([
  788. { key: 'materialNumber', name: '材料编号' },
  789. { key: 'mobilizationDate', name: '进场日期' },
  790. { key: 'materialName', name: '材料名称' },
  791. { key: 'materialType', name: '材料类型' },
  792. { key: 'specificationModel', name: '规格型号' },
  793. { key: 'supplierUnit', name: '供应商单位' },
  794. { key: 'proposedPosition', name: '拟用部位' },
  795. { key: 'userName', name: '记录人' },
  796. { key: 'action', name: '操作', width: 100, fixed: 'right', align: 'center' },
  797. ])
  798. const linksApproachTableData = ref([])
  799. //获取进场材料数据
  800. const linksApproachTableLoading = ref(false)
  801. const getApproachTableData = async () => {
  802. linksApproachTableLoading.value = true
  803. const { error, code, data } = await approachApi.queryPage({
  804. projectId: projectId.value,
  805. contractId: searchForm.value.contractId,
  806. ...ApproachSearchForm.value,
  807. })
  808. //处理数据
  809. linksApproachTableLoading.value = false
  810. if (!error && code === 200) {
  811. linksApproachTableData.value = getArrValue(data['records'])
  812. ApproachSearchForm.value.total = data.total || 0
  813. } else {
  814. linksApproachTableData.value = []
  815. ApproachSearchForm.value.total = 0
  816. }
  817. }
  818. //关联
  819. const linksApproachRow = (row) => {
  820. const toDayDate = new Dayjs().format('YYYY-MM-DD')
  821. const form = addEditFormModel.value
  822. form.materialName = row.materialName ?? '' //样品名称
  823. form.mobilizationDate = row.mobilizationDate ?? toDayDate //进场日期
  824. // form.specificationNumber = row.materialNumber ?? '' //样品编号
  825. form.specificationModel = row.specificationModel ?? '' //规格型号
  826. form.supplierUnit = row.supplierUnit ?? '' //供应商
  827. form.calculationUnit = row.calculationUnit ?? '' //计算单位
  828. form.batchNumber = row.batchNumber ?? '' //生产批号
  829. form.proposedPosition = row.proposedPosition ?? '' //拟用部位
  830. form.mobilizationId = row.id //关联ID
  831. //更新数据
  832. addEditFormModel.value = form
  833. mobilizationId.value = row.id //关联ID
  834. }
  835. //取消关联
  836. const cancelApproachRow = (row) => {
  837. if (row.id === mobilizationId.value) {
  838. addEditFormModel.value.mobilizationId = ''
  839. mobilizationId.value = ''
  840. }
  841. }
  842. const linksApproachModalSave = () => {
  843. linksApproachModal.value = false
  844. }
  845. //关闭关联进场材料
  846. const linksApproachModalClose = () => {
  847. linksApproachModal.value = false
  848. }
  849. //下载导入模板
  850. const downloadImportClick = () => {
  851. window.open('https://blade-oss-chongqing.oss-cn-shenzhen.aliyuncs.com//upload/20221109/1f1cc15e4e4918d8c793fa6ec0a2ae2a.xlsx', '_blank')
  852. }
  853. //委托
  854. const htmlRef = ref(null)
  855. const delegateModal = ref(false)
  856. const delegateHtml = ref('')
  857. const delegateHtmlForm = ref({})
  858. const delegateHtmlLoading = ref(false)
  859. const delegateContractId = ref(null)
  860. const delegationClick = () => {
  861. const rows = tableCheckedKeys.value
  862. if (rows.length <= 0) {
  863. window.$message.warning('请先勾选一条需要委托的数据')
  864. return
  865. } else if (rows.length > 1) {
  866. window.$message.warning('只能选择其中一条数据进行委托')
  867. return
  868. }
  869. const data = rows[0]
  870. if (!isNullES(data.testId)) {
  871. window.$message.warning('已上报的数据不允许委托')
  872. return
  873. }
  874. editHtmlId.value = data.id
  875. entrustId.value = data.entrustId
  876. delegateContractId.value = searchForm.value.contractId
  877. if (!isNullES(contractId)) {
  878. delegateContractChange()
  879. }
  880. }
  881. //合同段被选择
  882. const editHtmlId = ref('')
  883. const entrustId = ref('')
  884. const delegateContractChange = async () => {
  885. delegateHtmlLoading.value = true
  886. const res = await getCheckSample()
  887. if (!res) {
  888. delegateHtmlLoading.value = false
  889. return
  890. }
  891. delegateModal.value = true
  892. await getDelegateExcelHtml()
  893. await getDelegateDataInfo()
  894. await getEntrustNumberData()
  895. console.log(backObj.value, 'backObj.value')
  896. delegateHtmlLoading.value = false
  897. }
  898. //校验是否关联
  899. const getCheckSample = async () => {
  900. const { code, msg } = await samplingApi.getCheckSample({
  901. nodeId: primaryKeyId.value,
  902. sampleId: editHtmlId.value,
  903. contractId: delegateContractId.value,
  904. })
  905. //如果是200,说明没有关联,可以委托
  906. if (code === 200) {
  907. return true
  908. } else {
  909. window.$message.error(msg)
  910. return false
  911. }
  912. }
  913. //获取委托数据
  914. const getDelegateDataInfo = async () => {
  915. const { error, code, msg, data } = await samplingApi.getBussDataInfoTrialEntrust({
  916. id: entrustId.value,
  917. sampleId: editHtmlId.value,
  918. pkeyId: nodeErTreeId.value,
  919. contractId: delegateContractId.value,
  920. })
  921. if (!error && code === 200) {
  922. delegateHtmlForm.value = getObjValue(data[0])
  923. } else {
  924. delegateHtmlForm.value = {}
  925. window.$message.error(msg || '获取委托信息失败')
  926. }
  927. }
  928. const dataInfo = ref({})
  929. const getEntrustNumberData = async () => {
  930. const { error, code, data } = await dataApi.getEntrustNumber({
  931. contractId: contractId.value,
  932. pkeyId: searchForm.value.nodeId,
  933. })
  934. //处理数据
  935. if (!error && code === 200) {
  936. dataInfo.value = getObjVal(data)
  937. let mergedObject = null
  938. // 合并对象并赋值给新对象
  939. if (Object.keys(dataInfo.value).length > 0 && Object.keys(delegateHtmlForm.value).length > 0) {
  940. mergedObject = { ...dataInfo.value, ...delegateHtmlForm.value }
  941. } else if (Object.keys(dataInfo.value).length > 0) {
  942. mergedObject = { ...dataInfo.value }
  943. } else if (Object.keys(delegateHtmlForm.value).length > 0) {
  944. mergedObject = { ...delegateHtmlForm.value }
  945. } else {
  946. mergedObject = {}
  947. }
  948. // 可以在这里使用 mergedObject.value
  949. delegateHtmlForm.value = mergedObject
  950. } else {
  951. backObj.value = {}
  952. }
  953. }
  954. //获取委托html
  955. const getDelegateExcelHtml = async () => {
  956. const { error, code, msg, data } = await samplingApi.getExcelHtml({
  957. nodeId: primaryKeyId.value,
  958. contractId: contractId.value,
  959. })
  960. if (!error && code === 200) {
  961. delegateHtml.value = isString(data) ? data : ''
  962. nodeErTreeId.value = msg
  963. } else {
  964. delegateHtml.value = ''
  965. nodeErTreeId.value = ''
  966. window.$message.error(msg || '获取委托信息失败')
  967. }
  968. }
  969. //渲染完成
  970. const delegateHtmlRender = (form) => {
  971. delegateHtmlForm.value = form
  972. }
  973. //创建委托
  974. const creatingDelegateLoading = ref(false)
  975. const creatingDelegate = async () => {
  976. const rows = tableCheckedKeys.value
  977. if (isNullES(delegateHtml.value)) {
  978. window.$message.error('暂无委托单信息')
  979. return
  980. }
  981. const form = delegateHtmlForm.value
  982. if (isNullES(delegateContractId.value)) {
  983. window.$message.warning('请先选择合同段')
  984. return
  985. }
  986. creatingDelegateLoading.value = true
  987. form.contractId = delegateContractId.value
  988. form.nodeErTreeId = nodeErTreeId.value
  989. form.sampleId = editHtmlId.value
  990. form.nodeId = rows[0].nodeId
  991. const { error, code, msg } = await commissionApi.htmlSave(form)
  992. creatingDelegateLoading.value = false
  993. if (!error && code === 200) {
  994. window.$message.success('创建成功')
  995. delegateModalClose()
  996. } else {
  997. window.$message.error(msg || '创建失败')
  998. }
  999. }
  1000. //关闭委托
  1001. const delegateModalClose = () => {
  1002. delegateModal.value = false
  1003. delegateHtml.value = ''
  1004. delegateHtmlForm.value = {}
  1005. delegateHtmlLoading.value = false
  1006. creatingDelegateLoading.value = false
  1007. }
  1008. //页面卸载
  1009. onUnmounted(async () => {
  1010. if (!isNullES(device)) {
  1011. await device.close() // 关闭设备
  1012. await device.forget() // 遗忘设备
  1013. device = null
  1014. }
  1015. })
  1016. </script>
  1017. <style lang="scss" scoped>
  1018. @import "../../../styles/tentative/material/sampling.scss";
  1019. </style>
  1020. <style lang="scss">
  1021. .el-overlay-dialog .el-dialog.hc-new-dialog.hc-delegate-html-modal {
  1022. .hc-new-dialog-body {
  1023. padding: 0;
  1024. }
  1025. .hc-table-form-data-item {
  1026. padding: 0;
  1027. .el-scrollbar__bar.is-vertical {
  1028. right: 0;
  1029. }
  1030. }
  1031. }
  1032. .hc-delegate-html-modal {
  1033. .hc-delegate-html {
  1034. position: relative;
  1035. height: calc(100% - 40px);
  1036. .hc-table-form-data-item {
  1037. background-color: #efefef;
  1038. }
  1039. &::after {
  1040. content: "";
  1041. position: absolute;
  1042. inset: 0;
  1043. background: rgb(161 161 161 / 40%);
  1044. z-index: 22;
  1045. }
  1046. &.is-show {
  1047. &::after {
  1048. display: none;
  1049. z-index: -1;
  1050. }
  1051. }
  1052. }
  1053. }
  1054. </style>