addModal.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <template>
  2. <hc-new-dialog is-table widths="90%" :show="isShow" title="变更令" @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 } from '~uti/tools'
  165. import { 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. setSplitRef()
  196. getMeterChangeClassify()
  197. getMeterChangeType()
  198. getTableDetail()
  199. }
  200. })
  201. //初始化设置拖动分割线
  202. const setSplitRef = () => {
  203. //配置参考: https://split.js.org/#/?direction=vertical&snapOffset=0
  204. nextTick(() => {
  205. window.$split(['#hc_add_dialog_tree_card', '#hc_add_dialog_table_card'], {
  206. sizes: [20, 80],
  207. snapOffset: 0,
  208. minSize: [100, 400],
  209. })
  210. })
  211. }
  212. //计量变更归类
  213. const classifyData = ref([])
  214. const getMeterChangeClassify = async () => {
  215. classifyData.value = await getDictionaryData('meter_change_classify')
  216. }
  217. //计量变更类型
  218. const typeData = ref([])
  219. const getMeterChangeType = async () => {
  220. typeData.value = await getDictionaryData('meter_change_type')
  221. }
  222. //获取详情
  223. const getTableDetail = async () => {
  224. if (isNullES(dataId.value)) return
  225. const { data } = await mainApi.getDetail({ id: dataId.value })
  226. const info = getObjValue(data)
  227. baseForm.value = info
  228. tableData.value = getArrValue(info.nodeList)
  229. }
  230. //数据格式
  231. const treeProps = {
  232. label: 'nodeName',
  233. children: 'children',
  234. isLeaf: 'notExsitChild',
  235. }
  236. //懒加载的数据
  237. const treeLoadNode = async ({ item, level }, resolve) => {
  238. let id = 0
  239. if (level !== 0) {
  240. const nodeData = getObjValue(item)
  241. id = nodeData?.id || ''
  242. }
  243. //获取数据
  244. const { data } = await unitApi.lazyTree({
  245. contractId: contractId.value,
  246. id: id,
  247. })
  248. resolve(getArrValue(data))
  249. }
  250. //节点树被点击
  251. const treeCheckKeys = ref('')
  252. const treeNodeCheck = (_, { checkedKeys }) => {
  253. treeCheckKeys.value = checkedKeys?.join() ?? ''
  254. }
  255. //基础表单
  256. const baseFormRef = ref(null)
  257. const baseForm = ref({ fileList: [] })
  258. const baseFormRules = {
  259. changeNumber: {
  260. required: true,
  261. trigger: 'blur',
  262. message: '请输入变更令编号',
  263. },
  264. changeName: {
  265. required: true,
  266. trigger: 'blur',
  267. message: '请输入变更令名称',
  268. },
  269. businessDate: {
  270. required: true,
  271. trigger: 'blur',
  272. message: '请选择业务日期',
  273. },
  274. designDate: {
  275. required: true,
  276. trigger: 'blur',
  277. message: '请选择设计完成时间',
  278. },
  279. changeApprovalDate: {
  280. required: true,
  281. trigger: 'blur',
  282. message: '请选择变更批复日期',
  283. },
  284. }
  285. //变更申请部位列表
  286. const tableColumn = ref([
  287. { key: 'nodeName', name: '工程名称' },
  288. { key: 'nodeUrl', name: '节点路径' },
  289. { key: 'contractPicture', name: '合同图号' },
  290. { key: 'changeMoney', name: '变更后金额(元)' },
  291. { key: 'isSupplementName', name: '是否增补' },
  292. { key: 'action', name: '操作', width: 80, align: 'center' },
  293. ])
  294. const tableData = ref([])
  295. const addChangeNode = async () => {
  296. const nodeId = treeCheckKeys.value ?? ''
  297. if (isNullES(nodeId)) {
  298. window.$message.warning('请先选择节点')
  299. return
  300. }
  301. const { data } = await mainApi.getChangeNode({
  302. projectId: projectId.value,
  303. contractId: contractId.value,
  304. ids: nodeId,
  305. })
  306. const newArr = getArrValue(data)
  307. tableData.value.push(...newArr)
  308. }
  309. //删除变更申请部位
  310. const delChangeNode = (index) => {
  311. tableData.value.splice(index, 1)
  312. tableIndex.value = -1
  313. }
  314. //变更申请部位 行被点击
  315. const changeNodeItem = ref({})
  316. const tableIndex = ref(-1)
  317. const rowChangeNodeClick = ({ row, index }) => {
  318. if (!isArray(row.formList)) {
  319. tableData.value[index].formList = []
  320. }
  321. tableIndex.value = index
  322. changeNodeItem.value = row
  323. }
  324. //删除变更申请清单
  325. const tableFormListDel = (index) => {
  326. tableData.value[tableIndex.value].formList.splice(index, 1)
  327. getFormList()
  328. }
  329. //变更清单的添加弹窗
  330. const isChangeShow = ref(false)
  331. const changeIds = ref('')
  332. const changeShowClick = () => {
  333. if (isNullES(changeNodeItem.value['id'])) {
  334. window.$message.warning('请先选择变更申请部位')
  335. return false
  336. }
  337. changeIds.value = arrToKey(tableData.value[tableIndex.value].formList, 'id')
  338. isChangeShow.value = true
  339. }
  340. //确认选择完成
  341. const changeNodeFinish = (data) => {
  342. tableData.value[tableIndex.value].formList.push(...data)
  343. getFormList()
  344. }
  345. //变更清单增减
  346. const currentChangeTotalBlur = (row) => {
  347. const changeNum = (BigNumber(row.contractTotal).plus(row.currentChangeTotal)).toNumber()
  348. if (changeNum < 0) {
  349. window.$message.warning('变更增减数量不能小于变更前数量')
  350. const contract = '-' + row.contractTotal
  351. nextTick(() => {
  352. //计算金额
  353. row.currentChangeMoney = (BigNumber(contract).multipliedBy(row.currentPrice)).toNumber()
  354. row.changeMoney = 0
  355. //设置数量
  356. row.currentChangeTotal = contract
  357. row.changeTotal = 0
  358. })
  359. } else {
  360. nextTick(() => {
  361. //设置数量
  362. row.changeTotal = changeNum
  363. //计算金额
  364. row.currentChangeMoney = (BigNumber(row.currentChangeTotal).multipliedBy(row.currentPrice)).toNumber()
  365. row.changeMoney = (BigNumber(changeNum).multipliedBy(row.currentPrice)).toNumber()
  366. })
  367. }
  368. getFormList()
  369. }
  370. //获取变更清单总额
  371. const getFormList = () => {
  372. let total = 0, table = tableData.value
  373. for (let i = 0; i < table.length; i++) {
  374. const item = table[i]
  375. if (!isArray(item.formList)) {
  376. item.formList = []
  377. }
  378. let changeMoney = 0
  379. for (let j = 0; j < item.formList.length; j++) {
  380. const form = item.formList[j]
  381. total = (BigNumber(total).plus(form.currentChangeMoney)).toNumber()
  382. //变更后的金额统计
  383. changeMoney = (BigNumber(changeMoney).plus(form.changeMoney)).toNumber()
  384. }
  385. tableData.value[i].changeMoney = changeMoney
  386. }
  387. baseForm.value.changeMoney = total
  388. }
  389. //附件上传
  390. const uploadFormProps = {
  391. url: 'fileUrl',
  392. name: 'fileName',
  393. }
  394. const attachmentUpload = () => {
  395. uploadFileRef.value?.selectFile()
  396. }
  397. const attachmentUploadChange = (a, b, fileList) => {
  398. baseForm.value.fileList = getArrValue(fileList)
  399. }
  400. //文件上传
  401. const uploadFileRef = ref(null)
  402. const uploadFileOptions = ref({
  403. headers: getHeader(),
  404. multiple: false,
  405. })
  406. // 文件上传成功的回调
  407. const uploadFileSuccess = ({ resData }) => {
  408. baseForm.value.fileList.push({
  409. contractId: contractId.value,
  410. fileName: resData.originalName ?? '',
  411. filePdfUrl: resData.pdfUrl ?? '',
  412. fileUrl: resData.link ?? '',
  413. })
  414. uploadFileRef.value?.setModalShow(false)
  415. }
  416. //保存
  417. const addModalSave = async () => {
  418. const isValidate = await formValidate(baseFormRef.value)
  419. if (!isValidate) return false
  420. const form = baseForm.value, table = tableData.value
  421. if (table.length <= 0) {
  422. window.$message.warning('请先添加变更申请部位')
  423. return false
  424. }
  425. form.nodeList = table
  426. form.projectId = projectId.value
  427. form.contractId = contractId.value
  428. //发起请求
  429. let res = {}
  430. if (isNullES(dataId.value)) {
  431. //新增
  432. res = await mainApi.add(form)
  433. } else {
  434. //修改
  435. res = await mainApi.edit(form)
  436. }
  437. //处理数据
  438. const { code, msg } = res
  439. if (code === 200) {
  440. window.$message.success('保存成功')
  441. addModalClose()
  442. emit('finish')
  443. } else {
  444. window.$message.error(msg ?? '保存失败')
  445. }
  446. }
  447. //关闭弹窗
  448. const addModalClose = () => {
  449. isShow.value = false
  450. baseForm.value = { fileList: [] }
  451. tableData.value = []
  452. dataId.value = ''
  453. emit('close')
  454. }
  455. </script>