addModal.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. <template>
  2. <hc-new-dialog is-table widths="90%" :show="isShow" :title="`变更令${dataId ? '修改' : '新增'}`" @save="addModalSave" @close="addModalClose">
  3. <div class="relative h-full flex">
  4. <div id="hc_add_dialog_tree_card">
  5. <hc-card-item title="工程部位" scrollbar>
  6. <template #extra>
  7. <el-link type="primary" @click="addChangeNode">添加</el-link>
  8. </template>
  9. <hc-lazy-tree show-checkbox tree-key="id" :h-props="treeProps" @load="treeLoadNode" @check="treeNodeCheck" />
  10. </hc-card-item>
  11. </div>
  12. <div id="hc_add_dialog_table_card">
  13. <el-scrollbar>
  14. <!-- 基础表单 -->
  15. <hc-card-item title="基础表单">
  16. <el-form ref="baseFormRef" :model="baseForm" :rules="baseFormRules" label-position="left" label-width="auto">
  17. <el-row :gutter="20">
  18. <el-col :span="8">
  19. <el-form-item label="变更令编号:" prop="changeNumber">
  20. <el-input v-model="baseForm.changeNumber" />
  21. </el-form-item>
  22. </el-col>
  23. <el-col :span="8">
  24. <el-form-item label="变更令名称:" prop="changeName">
  25. <el-input v-model="baseForm.changeName" />
  26. </el-form-item>
  27. </el-col>
  28. <el-col :span="8">
  29. <el-form-item label="变更发起单位:">
  30. <el-input v-model="baseForm.changeUnit" />
  31. </el-form-item>
  32. </el-col>
  33. <el-col :span="8">
  34. <el-form-item label="业务日期:" prop="businessDate">
  35. <el-date-picker v-model="baseForm.businessDate" class="block" format="YYYY-MM-DD" type="date" value-format="YYYY-MM-DD" />
  36. </el-form-item>
  37. </el-col>
  38. <el-col :span="8">
  39. <el-form-item label="变更类型:">
  40. <el-select v-model="baseForm.changeType" filterable block>
  41. <el-option v-for="item in typeData" :key="item.value" :label="item.label" :value="item.value" />
  42. </el-select>
  43. </el-form-item>
  44. </el-col>
  45. <el-col :span="8">
  46. <el-form-item label="延长工期:">
  47. <el-input v-model="baseForm.lengthenDays" />
  48. </el-form-item>
  49. </el-col>
  50. <el-col :span="8">
  51. <el-form-item label="变更申请金额:">
  52. <el-input v-model="baseForm.changeMoney" disabled />
  53. </el-form-item>
  54. </el-col>
  55. <el-col :span="8">
  56. <el-form-item label="设计完成时间:" prop="designDate">
  57. <el-date-picker v-model="baseForm.designDate" class="block" format="YYYY-MM-DD" type="date" value-format="YYYY-MM-DD" />
  58. </el-form-item>
  59. </el-col>
  60. <el-col :span="8">
  61. <el-form-item label="实际变更桩号:">
  62. <el-input v-model="baseForm.realityChangeNumber" />
  63. </el-form-item>
  64. </el-col>
  65. <el-col :span="8">
  66. <el-form-item label="变更归类:">
  67. <el-select v-model="baseForm.changeClassify" filterable block>
  68. <el-option v-for="item in classifyData" :key="item.value" :label="item.label" :value="item.value" />
  69. </el-select>
  70. </el-form-item>
  71. </el-col>
  72. <el-col :span="8">
  73. <el-form-item label="变更批复文号:">
  74. <el-input v-model="baseForm.changeApprovalNumber" />
  75. </el-form-item>
  76. </el-col>
  77. <el-col :span="8">
  78. <el-form-item label="变更批复日期:" prop="changeApprovalDate">
  79. <el-date-picker v-model="baseForm.changeApprovalDate" class="block" format="YYYY-MM-DD" type="date" value-format="YYYY-MM-DD" />
  80. </el-form-item>
  81. </el-col>
  82. <!-- el-col :span="24">
  83. <el-form-item class="input-link-item" label="引用预变更:">
  84. <el-input v-model="baseForm.key6" disabled />
  85. <el-link type="primary" @click="quoteClick">引用</el-link>
  86. <el-link type="danger">删除引用</el-link>
  87. </el-form-item>
  88. </el-col -->
  89. <el-col :span="24">
  90. <el-form-item label="变更原因:">
  91. <el-input v-model="baseForm.changeCause" :autosize="{ minRows: 4, maxRows: 8 }" type="textarea" />
  92. </el-form-item>
  93. </el-col>
  94. </el-row>
  95. </el-form>
  96. </hc-card-item>
  97. <!-- 变更申请部位 -->
  98. <hc-card-item title="变更申请部位" class="mt-3">
  99. <hc-table :column="tableColumn" :datas="tableData" is-new is-current-row :index-style="{ width: 60 }" @row-click="rowChangeNodeClick">
  100. <template #contractPicture="{ row }">
  101. <hc-table-input v-model="row.contractPicture" />
  102. </template>
  103. <template #action="{ index }">
  104. <el-link type="danger" @click="delChangeNode(index)">删除</el-link>
  105. </template>
  106. </hc-table>
  107. </hc-card-item>
  108. <!-- 变更申请清单 -->
  109. <hc-card-item title="变更申请清单" class="mt-3">
  110. <template #extra>
  111. <el-link type="primary" @click="changeShowClick">添加</el-link>
  112. </template>
  113. <div class="hc-table-ref-box no-border">
  114. <el-table class="w-full" :data="tableData[tableIndex]?.formList" row-key="id" height="100%" highlight-current-row border>
  115. <el-table-column type="index" label="序号" />
  116. <el-table-column prop="formNumber" label="清单编号" />
  117. <el-table-column prop="formName" label="清单名称" />
  118. <el-table-column prop="currentPrice" label="单价" />
  119. <el-table-column label="数量" align="center">
  120. <el-table-column prop="contractTotal" label="变更前" />
  121. <el-table-column prop="currentChangeTotal" label="变更增减">
  122. <template #default="{ row }">
  123. <hc-table-input v-model="row.currentChangeTotal" @blur="currentChangeTotalBlur(row)" />
  124. </template>
  125. </el-table-column>
  126. <el-table-column prop="changeTotal" label="变更后" />
  127. </el-table-column>
  128. <el-table-column label="金额" align="center">
  129. <el-table-column prop="contractMoney" label="变更前" />
  130. <el-table-column prop="currentChangeMoney" label="变更增减" />
  131. <el-table-column prop="changeMoney" label="变更后" />
  132. </el-table-column>
  133. <el-table-column prop="action" label="操作" width="80" align="center">
  134. <template #default="scope">
  135. <el-link type="danger" @click="tableFormListDel(scope.$index)">删除</el-link>
  136. </template>
  137. </el-table-column>
  138. </el-table>
  139. </div>
  140. </hc-card-item>
  141. <!-- 附件列表 -->
  142. <hc-card-item class="mt-3" title="附件列表">
  143. <template #extra>
  144. <span class="text-orange font-400">可上传 图片(png、jpg、jpeg)、Excel(xls、xlsx)、PDF、Word(doc、docx)文件</span>
  145. </template>
  146. <el-form :model="baseForm" label-position="left" label-width="auto">
  147. <el-form-item label="上传附件">
  148. <hc-form-upload type="list" :src="baseForm.fileList" :h-props="uploadFormProps" @upload="attachmentUpload" @change="attachmentUploadChange" />
  149. </el-form-item>
  150. </el-form>
  151. </hc-card-item>
  152. </el-scrollbar>
  153. </div>
  154. </div>
  155. <!-- 变更申请清单 -->
  156. <ChangeRequest v-model="isChangeShow" :ids="changeIds" :tree-id="changeNodeItem.id" :contract-id="contractId" @finish="changeNodeFinish" />
  157. <!-- 文件上传组件 -->
  158. <hc-upload-file ref="uploadFileRef" :options="uploadFileOptions" @success="uploadFileSuccess" />
  159. </hc-new-dialog>
  160. </template>
  161. <script setup>
  162. import { nextTick, ref, watch } from 'vue'
  163. import { useAppStore } from '~src/store'
  164. import { getDictionaryData, isNumberReg } from '~uti/tools'
  165. import { arrIndex, arrToKey, formValidate, getArrValue, getObjValue, isArray, isNullES } from 'js-fast-way'
  166. import ChangeRequest from './changeRequest.vue'
  167. import unitApi from '~api/project/debit/contract/unit'
  168. import mainApi from '~api/alter/admin/order'
  169. import { getHeader } from 'hc-vue3-ui'
  170. import BigNumber from 'bignumber.js'
  171. const props = defineProps({
  172. ids: {
  173. type: [String, Number],
  174. default: '',
  175. },
  176. })
  177. //事件
  178. const emit = defineEmits(['finish', 'close'])
  179. const useAppState = useAppStore()
  180. const projectId = ref(useAppState.getProjectId || '')
  181. const contractId = ref(useAppState.getContractId || '')
  182. //双向绑定
  183. // eslint-disable-next-line no-undef
  184. const isShow = defineModel('modelValue', {
  185. default: false,
  186. })
  187. //监听
  188. const dataId = ref(props.ids)
  189. watch(() => props.ids, (ids) => {
  190. dataId.value = ids
  191. }, { immediate: true })
  192. //监听
  193. watch(isShow, (val) => {
  194. if (val) {
  195. getMeterChangeClassify()
  196. getMeterChangeType()
  197. getTableDetail()
  198. nextTick(() => {
  199. setSplitRef()
  200. })
  201. }
  202. })
  203. //初始化设置拖动分割线
  204. const setSplitRef = () => {
  205. //配置参考: https://split.js.org/#/?direction=vertical&snapOffset=0
  206. try {
  207. window.$split(['#hc_add_dialog_tree_card', '#hc_add_dialog_table_card'], {
  208. sizes: [20, 80],
  209. snapOffset: 0,
  210. minSize: [100, 400],
  211. })
  212. } catch (error) {
  213. console.log(error)
  214. }
  215. }
  216. //计量变更归类
  217. const classifyData = ref([])
  218. const getMeterChangeClassify = async () => {
  219. classifyData.value = await getDictionaryData('meter_change_classify')
  220. }
  221. //计量变更类型
  222. const typeData = ref([])
  223. const getMeterChangeType = async () => {
  224. typeData.value = await getDictionaryData('meter_change_type')
  225. }
  226. //获取详情
  227. const getTableDetail = async () => {
  228. if (isNullES(dataId.value)) return
  229. const { data } = await mainApi.getDetail({ id: dataId.value })
  230. const info = getObjValue(data)
  231. baseForm.value = info
  232. tableData.value = getArrValue(info.nodeList)
  233. }
  234. //数据格式
  235. const treeProps = {
  236. label: 'nodeName',
  237. children: 'children',
  238. isLeaf: 'notExsitChild',
  239. }
  240. //懒加载的数据
  241. const treeLoadNode = async ({ item, level }, resolve) => {
  242. let id = 0
  243. if (level !== 0) {
  244. const nodeData = getObjValue(item)
  245. id = nodeData?.id || ''
  246. }
  247. //获取数据
  248. const { data } = await unitApi.lazyTree({
  249. contractId: contractId.value,
  250. id: id,
  251. })
  252. resolve(getArrValue(data))
  253. }
  254. //节点树被点击
  255. const treeCheckKeys = ref('')
  256. const treeNodeCheck = (_, { checkedKeys }) => {
  257. treeCheckKeys.value = checkedKeys?.join() ?? ''
  258. }
  259. //基础表单
  260. const baseFormRef = ref(null)
  261. const baseForm = ref({ fileList: [] })
  262. const baseFormRules = {
  263. changeNumber: {
  264. required: true,
  265. trigger: 'blur',
  266. message: '请输入变更令编号',
  267. },
  268. changeName: {
  269. required: true,
  270. trigger: 'blur',
  271. message: '请输入变更令名称',
  272. },
  273. businessDate: {
  274. required: true,
  275. trigger: 'blur',
  276. message: '请选择业务日期',
  277. },
  278. designDate: {
  279. required: true,
  280. trigger: 'blur',
  281. message: '请选择设计完成时间',
  282. },
  283. changeApprovalDate: {
  284. required: true,
  285. trigger: 'blur',
  286. message: '请选择变更批复日期',
  287. },
  288. }
  289. //变更申请部位列表
  290. const tableColumn = ref([
  291. { key: 'nodeName', name: '工程名称' },
  292. { key: 'nodeUrl', name: '节点路径' },
  293. { key: 'contractPicture', name: '合同图号' },
  294. { key: 'changeMoney', name: '变更后金额(元)' },
  295. { key: 'isSupplementName', name: '是否增补' },
  296. { key: 'action', name: '操作', width: 80, align: 'center' },
  297. ])
  298. const tableData = ref([])
  299. const addChangeNode = async () => {
  300. const nodeId = treeCheckKeys.value ?? ''
  301. if (isNullES(nodeId)) {
  302. window.$message.warning('请先选择节点')
  303. return
  304. }
  305. const { data } = await mainApi.getChangeNode({
  306. projectId: projectId.value,
  307. contractId: contractId.value,
  308. changeIds: tableData.value.map((item) => item.id).join(),
  309. ids: nodeId,
  310. })
  311. const newArr = getArrValue(data)
  312. tableData.value.push(...newArr)
  313. }
  314. //删除变更申请部位
  315. const delChangeNode = (index) => {
  316. tableData.value.splice(index, 1)
  317. tableIndex.value = -1
  318. }
  319. //变更申请部位 行被点击
  320. const changeNodeItem = ref({})
  321. const tableIndex = ref(-1)
  322. const rowChangeNodeClick = ({ row }) => {
  323. const index = arrIndex(tableData.value, 'id', row.id)
  324. if (!isArray(row.formList)) {
  325. tableData.value[index].formList = []
  326. }
  327. // tableIndex.value = index
  328. tableIndex.value = index
  329. changeNodeItem.value = row
  330. }
  331. //删除变更申请清单
  332. const tableFormListDel = (index) => {
  333. tableData.value[tableIndex.value].formList.splice(index, 1)
  334. getFormList()
  335. }
  336. //变更清单的添加弹窗
  337. const isChangeShow = ref(false)
  338. const changeIds = ref('')
  339. const changeShowClick = () => {
  340. if (isNullES(changeNodeItem.value['id'])) {
  341. window.$message.warning('请先选择变更申请部位')
  342. return false
  343. }
  344. changeIds.value = arrToKey(tableData.value[tableIndex.value].formList, 'id')
  345. isChangeShow.value = true
  346. }
  347. //确认选择完成
  348. const changeNodeFinish = (data) => {
  349. tableData.value[tableIndex.value].formList.push(...data)
  350. getFormList()
  351. }
  352. //变更清单增减
  353. const currentChangeTotalBlur = (row) => {
  354. //如果为空
  355. let val = row.currentChangeTotal
  356. const isMeter = isNumberReg(val)
  357. if (isNullES(val) || !isMeter) {
  358. val = 0
  359. }
  360. const changeNum = (BigNumber(row.contractTotal).plus(val)).toString()
  361. if (changeNum < 0) {
  362. window.$message.warning('变更增减数量不能小于变更前数量')
  363. const contract = '-' + row.contractTotal
  364. nextTick(() => {
  365. //设置数量
  366. row.currentChangeTotal = contract
  367. row.changeTotal = 0
  368. //计算金额
  369. row.currentChangeMoney = (BigNumber(contract).multipliedBy(row.currentPrice)).toString()
  370. row.changeMoney = 0
  371. getFormList()
  372. })
  373. } else {
  374. nextTick(() => {
  375. //设置数量
  376. row.changeTotal = changeNum
  377. row.currentChangeTotal = val
  378. //计算金额
  379. row.currentChangeMoney = (BigNumber(val).multipliedBy(row.currentPrice)).toString()
  380. row.changeMoney = (BigNumber(changeNum).multipliedBy(row.currentPrice)).toString()
  381. getFormList()
  382. })
  383. }
  384. }
  385. //获取变更清单总额
  386. const getFormList = () => {
  387. let total = 0, table = tableData.value
  388. for (let i = 0; i < table.length; i++) {
  389. const item = table[i]
  390. if (!isArray(item.formList)) {
  391. item.formList = []
  392. }
  393. let changeMoney = 0
  394. for (let j = 0; j < item.formList.length; j++) {
  395. const form = item.formList[j]
  396. total = (BigNumber(total).plus(form.currentChangeMoney)).toString()
  397. //变更后的金额统计
  398. changeMoney = (BigNumber(changeMoney).plus(form.changeMoney)).toString()
  399. }
  400. item.changeMoney = changeMoney
  401. }
  402. //更新数据
  403. nextTick(() => {
  404. tableData.value = table
  405. baseForm.value.changeMoney = total
  406. })
  407. }
  408. //附件上传
  409. const uploadFormProps = {
  410. url: 'filePdfUrl',
  411. name: 'fileName',
  412. }
  413. const attachmentUpload = () => {
  414. uploadFileRef.value?.selectFile()
  415. }
  416. const attachmentUploadChange = (a, b, fileList) => {
  417. baseForm.value.fileList = getArrValue(fileList)
  418. }
  419. //文件上传
  420. const uploadFileRef = ref(null)
  421. const uploadFileOptions = ref({
  422. headers: getHeader(),
  423. multiple: false,
  424. })
  425. // 文件上传成功的回调
  426. const uploadFileSuccess = ({ resData }) => {
  427. const { pdfUrl } = resData
  428. if (isNullES(pdfUrl)) {
  429. window.$message.warning('该文件不能生成pdf,请更换文件上传')
  430. uploadFileRef.value?.setModalShow(false)
  431. return
  432. }
  433. baseForm.value.fileList.push({
  434. contractId: contractId.value,
  435. fileName: resData.originalName ?? '',
  436. filePdfUrl: resData.pdfUrl ?? '',
  437. fileUrl: resData.link ?? '',
  438. })
  439. uploadFileRef.value?.setModalShow(false)
  440. }
  441. //保存
  442. const addModalSave = async () => {
  443. const isValidate = await formValidate(baseFormRef.value)
  444. if (!isValidate) return false
  445. const form = baseForm.value, table = tableData.value
  446. if (table.length <= 0) {
  447. window.$message.warning('请先添加变更申请部位')
  448. return false
  449. }
  450. form.nodeList = table
  451. form.projectId = projectId.value
  452. form.contractId = contractId.value
  453. //发起请求
  454. let res = {}
  455. if (isNullES(dataId.value)) {
  456. //新增
  457. res = await mainApi.add(form)
  458. } else {
  459. //修改
  460. res = await mainApi.edit(form)
  461. }
  462. //处理数据
  463. const { code, msg } = res
  464. if (code === 200) {
  465. window.$message.success('保存成功')
  466. addModalClose()
  467. emit('finish')
  468. } else {
  469. window.$message.error(msg ?? '保存失败')
  470. }
  471. }
  472. //关闭弹窗
  473. const addModalClose = () => {
  474. isShow.value = false
  475. baseForm.value = { fileList: [] }
  476. tableData.value = []
  477. tableIndex.value = -1
  478. emit('close')
  479. }
  480. </script>