form.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. <template>
  2. <HcCard action-ui="text-center">
  3. <HcCardItem id="hc-program-annual-form-card-item" class="hc-program-annual-form-card-item">
  4. <el-form ref="formRef" inline :model="formModel" :rules="formRules">
  5. <div>
  6. <el-form-item label="预算名称" prop="name" class="w-1/2 mr-6">
  7. <el-input v-model="formModel.name" placeholder="请输入预算名称" />
  8. </el-form-item>
  9. <el-form-item label="预算起止时间" prop="time">
  10. <HcDatePicker :dates="betweenTime" clearable @change="betweenTimeUpdate" />
  11. </el-form-item>
  12. </div>
  13. <div>
  14. <el-form-item label="合同" prop="annualContractTarget">
  15. <el-tooltip content="年度合同指标">
  16. <el-input v-model="formModel.annualContractTarget" placeholder="年度合同指标" disabled />
  17. </el-tooltip>
  18. </el-form-item>
  19. <el-form-item label="利润" prop="annualProfitTarget">
  20. <el-tooltip content="年度利润指标">
  21. <el-input v-model="formModel.annualProfitTarget" placeholder="年度利润指标" disabled />
  22. </el-tooltip>
  23. </el-form-item>
  24. <el-form-item label="预算" prop="totalBudget">
  25. <el-tooltip content="总经营预算">
  26. <el-input v-model="formModel.totalBudget" placeholder="总经营预算" disabled>
  27. <template #append>
  28. </template>
  29. </el-input>
  30. </el-tooltip>
  31. </el-form-item>
  32. <el-form-item label="工资" prop="staffCost">
  33. <el-tooltip content="人员成本">
  34. <el-input v-model="formModel.staffCost" placeholder="人员成本" disabled>
  35. <template #append>
  36. </template>
  37. </el-input>
  38. </el-tooltip>
  39. </el-form-item>
  40. <el-form-item label="综合" prop="manageDisburse">
  41. <el-tooltip content="管理支出">
  42. <el-input v-model="formModel.manageDisburse" placeholder="管理支出" disabled>
  43. <template #append>
  44. </template>
  45. </el-input>
  46. </el-tooltip>
  47. </el-form-item>
  48. </div>
  49. </el-form>
  50. </HcCardItem>
  51. <div class="hc-program-annual-form-tabs" :style="tabsStyle">
  52. <el-tabs v-model="editableTabsValue" type="border-card" class="form-tabs" @tab-change="changeTab">
  53. <el-tab-pane label="年度预算收入">
  54. <HcTable :is-index="false" :column="tableColumn" :datas="incomeTable">
  55. <template #projectId="{ row, index }">
  56. <el-select v-model="row.projectId" style="width: 100%;">
  57. <el-option v-for="item in projectData" :label="item.name" :value="item.id" />
  58. </el-select>
  59. </template>
  60. <template #incomeType="{ row, index }">
  61. <el-select v-model="row.incomeType">
  62. <el-option v-for="item in incomeTypeData" :label="item.dictName" :value="item.dictValue" />
  63. </el-select>
  64. </template>
  65. <template #projectTypeValue="{ row, index }">
  66. <el-input v-model="row.projectTypeValue" disabled :getdata="getprojectType(row)" />
  67. </template>
  68. <template #contractTypeValue="{ row, index }">
  69. <el-input v-model="row.contractTypeValue" disabled :getdata="getprojectType(row)" />
  70. </template>
  71. <template #predictSignDate="{ row, index }">
  72. <el-date-picker v-model="row.predictSignDate" class="block" format="YYYY-MM-DD" type="date" value-format="YYYY-MM-DD" />
  73. </template>
  74. <template #predictContractMoney="{ row, index }">
  75. <el-input v-model="row.predictContractMoney" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  76. </template>
  77. <template #predictAnnualReturned="{ row, index }">
  78. <el-input v-model="row.predictAnnualReturned" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  79. </template>
  80. <template #action="{ row, index }">
  81. <el-button size="small" type="primary" @click="addRow">
  82. <HcIcon name="add" />
  83. <span>新增</span>
  84. </el-button>
  85. <el-button size="small" type="danger" @click="delRow(index)">
  86. <HcIcon name="delete-bin" />
  87. <span>删除</span>
  88. </el-button>
  89. </template>
  90. </HcTable>
  91. </el-tab-pane>
  92. <el-tab-pane label="年度预算支出">
  93. <HcTable :is-index="false" :column="tableColumn1" :datas="costTable">
  94. <template #budgetSubject="{ row, index }">
  95. <el-select v-model="row.budgetSubject">
  96. <el-option v-for="item in budgetTypeList" :label="item.dictName" :value="item.dictValue" />
  97. </el-select>
  98. </template>
  99. <template #secondSubject="{ row, index }">
  100. <el-select v-model="row.secondSubject" :getdata="getsecondBudgetTypeList(row.budgetSubject, index)">
  101. <el-option v-for="item in secondBudgetTypeList[index]" :label="item.dictName" :value="item.dictValue" />
  102. </el-select>
  103. </template>
  104. <template #january="{ row, index }">
  105. <el-input v-model="row.january" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  106. </template>
  107. <template #february="{ row, index }">
  108. <el-input v-model="row.february" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  109. </template>
  110. <template #march="{ row, index }">
  111. <el-input v-model="row.march" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  112. </template>
  113. <template #april="{ row, index }">
  114. <el-input v-model="row.april" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  115. </template>
  116. <template #may="{ row, index }">
  117. <el-input v-model="row.may" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  118. </template>
  119. <template #june="{ row, index }">
  120. <el-input v-model="row.june" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  121. </template>
  122. <template #july="{ row, index }">
  123. <el-input v-model="row.july" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  124. </template>
  125. <template #august="{ row, index }">
  126. <el-input v-model="row.august" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  127. </template>
  128. <template #september="{ row, index }">
  129. <el-input v-model="row.september" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  130. </template>
  131. <template #october="{ row, index }">
  132. <el-input v-model="row.october" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  133. </template>
  134. <template #november="{ row, index }">
  135. <el-input v-model="row.november" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  136. </template>
  137. <template #december="{ row, index }">
  138. <el-input v-model="row.december" onkeyup="this.value=this.value.match(/\d+\.?\d{0,2}/)" />
  139. </template>
  140. <template #action="{ row, index }">
  141. <el-button size="small" type="primary" @click="addRow1">
  142. <HcIcon name="add" />
  143. <span>新增</span>
  144. </el-button>
  145. <el-button size="small" type="danger" @click="delRow1(row, index)">
  146. <HcIcon name="delete-bin" />
  147. <span>删除</span>
  148. </el-button>
  149. </template>
  150. </HcTable>
  151. </el-tab-pane>
  152. </el-tabs>
  153. </div>
  154. <template #action>
  155. <el-button size="large" type="info" hc-btn @click="goBackClick">
  156. <HcIcon name="arrow-go-back" />
  157. <span>取消并返回</span>
  158. </el-button>
  159. <el-button size="large" type="primary" hc-btn :loading="saveLoaing" @click="saveClick">
  160. <HcIcon name="check-double" />
  161. <span>提交保存</span>
  162. </el-button>
  163. </template>
  164. </HcCard>
  165. </template>
  166. <script setup>
  167. import { nextTick, onActivated, onDeactivated, ref, watch } from 'vue'
  168. import { useRoute, useRouter } from 'vue-router'
  169. import annualApi from '~api/program/annual.js'
  170. import costApi from '~api/project/cost.js'
  171. import { getChildList } from '~api/system/parameter.js'
  172. import { formValidate, getArrValue, getObjValue } from 'js-fast-way'
  173. import { getDictInfo, getProjectList } from '~api/other'
  174. const router = useRouter()
  175. const useRoutes = useRoute()
  176. const dataId = ref(useRoutes?.query?.id ?? '')
  177. const dataType = ref(useRoutes?.query?.type ?? '')
  178. //页面激活
  179. onActivated(() => {
  180. editableTabsValue.value = '0'
  181. setFormTabsStyle()
  182. windowResize()
  183. dataId.value = useRoutes?.query?.id ?? ''
  184. dataType.value = useRoutes?.query?.type ?? ''
  185. if (dataId.value.length > 0) {
  186. getDetail()
  187. } else {
  188. formModel.value = {}
  189. incomeTable.value = [{}]
  190. costTable.value = [{}]
  191. betweenTime.value = []
  192. }
  193. getProjectData()
  194. getIncomeType()
  195. getBudgetTypeList()
  196. })
  197. const costTable = ref([])
  198. const incomeTable = ref([])
  199. //深度监听
  200. watch(() => [
  201. costTable.value,
  202. incomeTable.value,
  203. ], ([cost, income]) => {
  204. formModel.value.incomeList = cost
  205. formModel.value.disburseList = income
  206. }, { deep: true })
  207. const getDetail = async () => {
  208. const { error, code, data } = await annualApi.getAnnualBudget({ id:dataId.value })
  209. if (!error && code === 200) {
  210. formModel.value = getObjValue(data)
  211. incomeTable.value = data?.incomeList.length > 0 ? data?.incomeList : [{}]
  212. costTable.value = data?.disburseList.length > 0 ? data?.disburseList : [{}]
  213. betweenTime.value[0] = data['budgetStartTime']
  214. betweenTime.value[1] = data['budgetEndTime']
  215. } else {
  216. formModel.value = {}
  217. }
  218. }
  219. //获取项目数据
  220. const projectData = ref([])
  221. const getProjectData = async () => {
  222. const { error, code, data } = await annualApi.getProjectList()
  223. //判断状态
  224. if (!error && code === 200) {
  225. projectData.value = getArrValue(data)
  226. } else {
  227. projectData.value = []
  228. }
  229. }
  230. const getprojectType = (row)=>{
  231. projectData.value.forEach((ele)=>{
  232. if (row.projectId === ele.id) {
  233. row.contractTypeValue = ele.contractTypeValue
  234. row.projectTypeValue = ele.projectTypeValue
  235. }
  236. })
  237. }
  238. //收入类型字典
  239. const incomeTypeData = ref([])
  240. const getIncomeType = async () => {
  241. const { error, code, data } = await getDictInfo('project_income_type')
  242. //判断状态
  243. if (!error && code === 200) {
  244. incomeTypeData.value = getArrValue(data)
  245. } else {
  246. incomeTypeData.value = []
  247. }
  248. }
  249. //获取预算分类getSecondSubject
  250. const budgetTypeList = ref([])
  251. const getBudgetTypeList = async ()=>{
  252. const { error, code, data } = await costApi.getSecondSubject()
  253. if (!error && code === 200) {
  254. budgetTypeList.value = getArrValue(data)
  255. } else {
  256. budgetTypeList.value = {}
  257. }
  258. }
  259. const secondBudgetTypeList = ref({})
  260. const getsecondBudgetTypeList = async (val, index)=>{
  261. let id = ''
  262. budgetTypeList.value.forEach((ele)=>{
  263. if (ele.dictValue === val) {
  264. id = ele.id
  265. }
  266. })
  267. if (id.length > 0) {
  268. const { error, code, data } = await costApi.getChlidList({ parentId:id, type:1 })
  269. if (!error && code === 200) {
  270. secondBudgetTypeList.value[index] = getArrValue(data)
  271. } else {
  272. secondBudgetTypeList.value[index] = []
  273. }
  274. }
  275. }
  276. //设置表单tabs样式
  277. const tabsStyle = ref('')
  278. const setFormTabsStyle = () => {
  279. //处理为响应式高度
  280. nextTick(() => {
  281. const cardItemHeight = document.getElementById('hc-program-annual-form-card-item')?.offsetHeight
  282. tabsStyle.value = 'height: calc(100% - ' + cardItemHeight + 'px)'
  283. })
  284. }
  285. //顶部表单数据
  286. const formRef = ref(null)
  287. const formModel = ref({
  288. key1: '', key2: '', key3: '', key4: '', key5: '',
  289. })
  290. const formRules = {
  291. name: [{ required: true, message: '请输入预算名称', trigger: 'change' }],
  292. }
  293. //日期时间被选择
  294. const betweenTime = ref([])
  295. const betweenTimeUpdate = ({ arr, query }) => {
  296. betweenTime.value = arr
  297. formModel.value.budgetStartTime = arr[0]
  298. formModel.value.budgetEndTime = arr[1]
  299. }
  300. //监听浏览器窗口变化
  301. const windowResize = () => {
  302. window.addEventListener('resize', resizeEvent)
  303. }
  304. const resizeEvent = () => {
  305. window.requestAnimationFrame(() => {
  306. setFormTabsStyle()
  307. })
  308. }
  309. //tabs切换
  310. const editableTabsValue = ref('0')
  311. //获取数据
  312. const tableColumn = [
  313. { key: 'projectId', name: '项目名称', minWidth: '180', align: 'center' },
  314. { key: 'incomeType', name: '收入类别', width: '180', align: 'center' },
  315. { key: 'projectTypeValue', name: '项目类别', width: '180', align: 'center' },
  316. { key: 'contractTypeValue', name: '产品线', width: '180', align: 'center' },
  317. { key: 'predictSignDate', name: '预计签单时间', width: '220', align: 'center' },
  318. { key: 'predictContractMoney', name: '预计新签合同额', width: '180', align: 'center' },
  319. { key: 'predictAnnualReturned', name: '预计本年度回款额', width: '180', align: 'center' },
  320. { key: 'action', name: '操作', width: '200', align: 'center', fixed: 'right' },
  321. ]
  322. //切换tab页
  323. const changeTab = (val)=>{
  324. console.log(val, 'val')
  325. console.log(incomeTable.value, 'incomeTable')
  326. console.log(costTable.value, 'incomeTable')
  327. }
  328. const tableData = ref([
  329. { id: 1 }, { id: 2 },
  330. ])
  331. const addRow = ()=>{
  332. incomeTable.value.push({})
  333. }
  334. const delRow = (row, index)=>{
  335. incomeTable.value.splice(index, 1)
  336. if (incomeTable.value.length == 0) {
  337. incomeTable.value.push({})
  338. }
  339. }
  340. const addRow1 = ()=>{
  341. costTable.value.push({})
  342. }
  343. const delRow1 = (row, index)=>{
  344. costTable.value.splice(index, 1)
  345. if (costTable.value.length == 0) {
  346. costTable.value.push({})
  347. }
  348. }
  349. const tableColumn1 = [
  350. { key: 'budgetSubject', name: '预算科目(一级)', minWidth: '180', align: 'center' },
  351. { key: 'secondSubject', name: '二级科目', minWidth: '180', align: 'center' },
  352. { key: 'january', name: '1月', width: '100', align: 'center' },
  353. { key: 'february', name: '2月', width: '100', align: 'center' },
  354. { key: 'march', name: '3月', width: '100', align: 'center' },
  355. { key: 'april', name: '4月', width: '100', align: 'center' },
  356. { key: 'may', name: '5月', width: '100', align: 'center' },
  357. { key: 'june', name: '6月', width: '100', align: 'center' },
  358. { key: 'july', name: '7月', width: '100', align: 'center' },
  359. { key: 'august', name: '8月', width: '100', align: 'center' },
  360. { key: 'september', name: '9月', width: '100', align: 'center' },
  361. { key: 'october', name: '10月', width: '100', align: 'center' },
  362. { key: 'november', name: '11月', width: '100', align: 'center' },
  363. { key: 'december', name: '12月', width: '100', align: 'center' },
  364. { key: 'action', name: '操作', width: '200', align: 'center', fixed: 'right' },
  365. ]
  366. const tableData2 = ref([
  367. { id: 1 }, { id: 2 },
  368. ])
  369. //返回
  370. const goBackClick = () => {
  371. router.back()
  372. }
  373. //新增
  374. const addAnnualBudget = async (obj)=>{
  375. console.log(obj, '新增')
  376. saveLoaing.value = true
  377. const { error, code, data, msg } = await annualApi.addAnnualBudget( obj)
  378. saveLoaing.value = false
  379. if (!error && code === 200) {
  380. window.$message.success(msg)
  381. router.push({
  382. name: 'program-annual',
  383. })
  384. }
  385. }
  386. //修改
  387. const updateAnnualBudget = async (obj)=>{
  388. saveLoaing.value = true
  389. const { error, code, data, msg } = await annualApi.updateAnnualBudget( obj)
  390. saveLoaing.value = false
  391. if (!error && code === 200) {
  392. window.$message.success(msg)
  393. router.push({
  394. name: 'program-annual',
  395. })
  396. }
  397. }
  398. const isEmptyObj = (obj)=> {
  399. let arr = Object.keys(obj)
  400. return (arr.length == 0)
  401. }
  402. //提交保存
  403. const saveLoaing = ref(false)
  404. const saveClick = async () => {
  405. const res = await formValidate(formRef.value)
  406. formModel.value.incomeList = incomeTable.value
  407. formModel.value.disburseList = costTable.value
  408. if (res) {
  409. //限制空数据提交
  410. formModel.value.disburseList = formModel.value.disburseList.filter((item)=>!isEmptyObj(item))
  411. formModel.value.incomeList = formModel.value.incomeList.filter((item)=>!isEmptyObj(item))
  412. if (dataType.value == 'edit') {
  413. updateAnnualBudget(formModel.value)
  414. } else {
  415. addAnnualBudget(formModel.value)
  416. }
  417. }
  418. }
  419. //被卸载时
  420. onDeactivated(() => {
  421. window.removeEventListener('resize', resizeEvent)
  422. })
  423. </script>
  424. <style lang="scss" scoped>
  425. .hc-program-annual-form-card-item {
  426. height: auto;
  427. }
  428. .hc-program-annual-form-tabs {
  429. position: relative;
  430. padding-top: 24px;
  431. .el-tabs.form-tabs {
  432. height: 100%;
  433. }
  434. }
  435. </style>
  436. <style lang="scss">
  437. .hc-program-annual-form-tabs .el-tabs.form-tabs .el-tabs__content {
  438. height: calc(100% - 39px);
  439. .el-tab-pane {
  440. height: 100%;
  441. }
  442. }
  443. </style>