addModal.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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
  149. v-model="baseForm.fileList"
  150. is-res
  151. :options="{
  152. type: 'list',
  153. props: uploadFormProps,
  154. isArr: true,
  155. num: 0,
  156. }"
  157. :upload="{ options: { multiple: false } }"
  158. @success="uploadFileSuccess"
  159. />
  160. </el-form-item>
  161. </el-form>
  162. </hc-card-item>
  163. </el-scrollbar>
  164. </div>
  165. </div>
  166. <!-- 变更申请清单 -->
  167. <ChangeRequest v-model="isChangeShow" :ids="changeIds" :tree-id="changeNodeItem.id" :contract-id="contractId" @finish="changeNodeFinish" />
  168. </hc-new-dialog>
  169. </template>
  170. <script setup>
  171. import { nextTick, ref, watch } from 'vue'
  172. import { useAppStore } from '~src/store'
  173. import { getDictionaryData, isNumberReg } from '~uti/tools'
  174. import { arrIndex, arrToKey, formValidate, getArrValue, getObjValue, isArray, isNullES } from 'js-fast-way'
  175. import ChangeRequest from './changeRequest.vue'
  176. import unitApi from '~api/project/debit/contract/unit'
  177. import mainApi from '~api/alter/admin/order'
  178. import BigNumber from 'bignumber.js'
  179. const props = defineProps({
  180. ids: {
  181. type: [String, Number],
  182. default: '',
  183. },
  184. })
  185. //事件
  186. const emit = defineEmits(['finish', 'close'])
  187. const useAppState = useAppStore()
  188. const projectId = ref(useAppState.getProjectId || '')
  189. const contractId = ref(useAppState.getContractId || '')
  190. //双向绑定
  191. // eslint-disable-next-line no-undef
  192. const isShow = defineModel('modelValue', {
  193. default: false,
  194. })
  195. //监听
  196. const dataId = ref(props.ids)
  197. watch(() => props.ids, (ids) => {
  198. dataId.value = ids
  199. }, { immediate: true })
  200. //监听
  201. watch(isShow, (val) => {
  202. if (val) {
  203. getMeterChangeClassify()
  204. getMeterChangeType()
  205. getTableDetail()
  206. nextTick(() => {
  207. setSplitRef()
  208. })
  209. }
  210. })
  211. //初始化设置拖动分割线
  212. const setSplitRef = () => {
  213. //配置参考: https://split.js.org/#/?direction=vertical&snapOffset=0
  214. try {
  215. window.$split(['#hc_add_dialog_tree_card', '#hc_add_dialog_table_card'], {
  216. sizes: [20, 80],
  217. snapOffset: 0,
  218. minSize: [100, 400],
  219. })
  220. } catch (error) {
  221. console.log(error)
  222. }
  223. }
  224. //计量变更归类
  225. const classifyData = ref([])
  226. const getMeterChangeClassify = async () => {
  227. classifyData.value = await getDictionaryData('meter_change_classify')
  228. }
  229. //计量变更类型
  230. const typeData = ref([])
  231. const getMeterChangeType = async () => {
  232. typeData.value = await getDictionaryData('meter_change_type')
  233. }
  234. //获取详情
  235. const getTableDetail = async () => {
  236. if (isNullES(dataId.value)) return
  237. const { data } = await mainApi.getDetail({ id: dataId.value })
  238. const info = getObjValue(data)
  239. baseForm.value = info
  240. tableData.value = getArrValue(info.nodeList)
  241. }
  242. //数据格式
  243. const treeProps = {
  244. label: 'nodeName',
  245. children: 'children',
  246. isLeaf: 'notExsitChild',
  247. }
  248. //懒加载的数据
  249. const treeLoadNode = async ({ item, level }, resolve) => {
  250. let id = 0
  251. if (level !== 0) {
  252. const nodeData = getObjValue(item)
  253. id = nodeData?.id || ''
  254. }
  255. //获取数据
  256. const { data } = await unitApi.lazyTree({
  257. contractId: contractId.value,
  258. id: id,
  259. })
  260. resolve(getArrValue(data))
  261. }
  262. //节点树被点击
  263. const treeCheckKeys = ref('')
  264. const treeNodeCheck = (_, { checkedKeys }) => {
  265. treeCheckKeys.value = checkedKeys?.join() ?? ''
  266. }
  267. //基础表单
  268. const baseFormRef = ref(null)
  269. const baseForm = ref({ fileList: [] })
  270. const baseFormRules = {
  271. changeNumber: {
  272. required: true,
  273. trigger: 'blur',
  274. message: '请输入变更令编号',
  275. },
  276. changeName: {
  277. required: true,
  278. trigger: 'blur',
  279. message: '请输入变更令名称',
  280. },
  281. businessDate: {
  282. required: true,
  283. trigger: 'blur',
  284. message: '请选择业务日期',
  285. },
  286. designDate: {
  287. required: true,
  288. trigger: 'blur',
  289. message: '请选择设计完成时间',
  290. },
  291. changeApprovalDate: {
  292. required: true,
  293. trigger: 'blur',
  294. message: '请选择变更批复日期',
  295. },
  296. }
  297. //变更申请部位列表
  298. const tableColumn = ref([
  299. { key: 'nodeName', name: '工程名称' },
  300. { key: 'nodeUrl', name: '节点路径' },
  301. { key: 'contractPicture', name: '合同图号' },
  302. { key: 'changeMoney', name: '变更后金额(元)' },
  303. { key: 'isSupplementName', name: '是否增补' },
  304. { key: 'action', name: '操作', width: 80, align: 'center' },
  305. ])
  306. const tableData = ref([])
  307. const addChangeNode = async () => {
  308. const nodeId = treeCheckKeys.value ?? ''
  309. if (isNullES(nodeId)) {
  310. window.$message.warning('请先选择节点')
  311. return
  312. }
  313. const { data } = await mainApi.getChangeNode({
  314. projectId: projectId.value,
  315. contractId: contractId.value,
  316. changeIds: tableData.value.map((item) => item.id).join(),
  317. ids: nodeId,
  318. })
  319. const newArr = getArrValue(data)
  320. tableData.value.push(...newArr)
  321. }
  322. //删除变更申请部位
  323. const delChangeNode = (index) => {
  324. tableData.value.splice(index, 1)
  325. tableIndex.value = -1
  326. }
  327. //变更申请部位 行被点击
  328. const changeNodeItem = ref({})
  329. const tableIndex = ref(-1)
  330. const rowChangeNodeClick = ({ row }) => {
  331. const index = arrIndex(tableData.value, 'id', row.id)
  332. if (!isArray(row.formList)) {
  333. tableData.value[index].formList = []
  334. }
  335. // tableIndex.value = index
  336. tableIndex.value = index
  337. changeNodeItem.value = row
  338. }
  339. //删除变更申请清单
  340. const tableFormListDel = (index) => {
  341. tableData.value[tableIndex.value].formList.splice(index, 1)
  342. getFormList()
  343. }
  344. //变更清单的添加弹窗
  345. const isChangeShow = ref(false)
  346. const changeIds = ref('')
  347. const changeShowClick = () => {
  348. if (isNullES(changeNodeItem.value['id'])) {
  349. window.$message.warning('请先选择变更申请部位')
  350. return false
  351. }
  352. changeIds.value = arrToKey(tableData.value[tableIndex.value].formList, 'id')
  353. isChangeShow.value = true
  354. }
  355. //确认选择完成
  356. const changeNodeFinish = (data) => {
  357. tableData.value[tableIndex.value].formList.push(...data)
  358. getFormList()
  359. }
  360. //变更清单增减
  361. const currentChangeTotalBlur = (row) => {
  362. //如果为空
  363. let val = row.currentChangeTotal
  364. const isMeter = isNumberReg(val)
  365. if (isNullES(val) || !isMeter) {
  366. val = 0
  367. }
  368. const changeNum = (BigNumber(row.contractTotal).plus(val)).toString()
  369. if (changeNum < 0) {
  370. window.$message.warning('变更增减数量不能小于变更前数量')
  371. const contract = '-' + row.contractTotal
  372. nextTick(() => {
  373. //设置数量
  374. row.currentChangeTotal = contract
  375. row.changeTotal = 0
  376. //计算金额
  377. row.currentChangeMoney = (BigNumber(contract).multipliedBy(row.currentPrice)).toString()
  378. row.changeMoney = 0
  379. getFormList()
  380. })
  381. } else {
  382. nextTick(() => {
  383. //设置数量
  384. row.changeTotal = changeNum
  385. row.currentChangeTotal = val
  386. //计算金额
  387. row.currentChangeMoney = (BigNumber(val).multipliedBy(row.currentPrice)).toString()
  388. row.changeMoney = (BigNumber(changeNum).multipliedBy(row.currentPrice)).toString()
  389. getFormList()
  390. })
  391. }
  392. }
  393. //获取变更清单总额
  394. const getFormList = () => {
  395. let total = 0, table = tableData.value
  396. for (let i = 0; i < table.length; i++) {
  397. const item = table[i]
  398. if (!isArray(item.formList)) {
  399. item.formList = []
  400. }
  401. let changeMoney = 0
  402. for (let j = 0; j < item.formList.length; j++) {
  403. const form = item.formList[j]
  404. total = (BigNumber(total).plus(form.currentChangeMoney)).toString()
  405. //变更后的金额统计
  406. changeMoney = (BigNumber(changeMoney).plus(form.changeMoney)).toString()
  407. }
  408. item.changeMoney = changeMoney
  409. }
  410. //更新数据
  411. nextTick(() => {
  412. tableData.value = table
  413. baseForm.value.changeMoney = total
  414. })
  415. }
  416. //附件上传
  417. const uploadFormProps = {
  418. url: 'filePdfUrl',
  419. name: 'fileName',
  420. }
  421. // 文件上传成功的回调
  422. const uploadFileSuccess = ({ res }, resolve) => {
  423. const { link, pdfUrl, originalName } = getObjValue(res.data)
  424. if (isNullES(pdfUrl)) {
  425. window.$message.warning('该文件不能生成pdf,请更换文件上传')
  426. resolve()
  427. return
  428. }
  429. resolve({
  430. contractId: contractId.value,
  431. fileName: originalName ?? '',
  432. filePdfUrl: pdfUrl ?? '',
  433. fileUrl: link ?? '',
  434. })
  435. }
  436. //保存
  437. const addModalSave = async () => {
  438. const isValidate = await formValidate(baseFormRef.value)
  439. if (!isValidate) return false
  440. const form = baseForm.value, table = tableData.value
  441. if (table.length <= 0) {
  442. window.$message.warning('请先添加变更申请部位')
  443. return false
  444. }
  445. form.nodeList = table
  446. form.projectId = projectId.value
  447. form.contractId = contractId.value
  448. //发起请求
  449. let res = {}
  450. if (isNullES(dataId.value)) {
  451. //新增
  452. res = await mainApi.add(form)
  453. } else {
  454. //修改
  455. res = await mainApi.edit(form)
  456. }
  457. //处理数据
  458. const { code, msg } = res
  459. if (code === 200) {
  460. window.$message.success('保存成功')
  461. addModalClose()
  462. emit('finish')
  463. } else {
  464. window.$message.error(msg ?? '保存失败')
  465. }
  466. }
  467. //关闭弹窗
  468. const addModalClose = () => {
  469. isShow.value = false
  470. baseForm.value = { fileList: [] }
  471. tableData.value = []
  472. tableIndex.value = -1
  473. emit('close')
  474. }
  475. </script>