list-info.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. <template>
  2. <HcCard action-ui="text-center">
  3. <div class="hac-card-project-box">
  4. <div class="left-box">
  5. <el-scrollbar>
  6. <el-form ref="formRef" :model="formModel" :rules="formRules" label-width="auto" size="large" :disabled="dataType === 'view'">
  7. <div class="project-form-top">
  8. <HcCardItem title="基础信息">
  9. <el-form-item label="项目名称:" prop="name">
  10. <el-input v-model="formModel.name" />
  11. </el-form-item>
  12. <el-form-item label="建设单位:" prop="constructUnit">
  13. <el-input v-model="formModel.constructUnit" />
  14. </el-form-item>
  15. <el-form-item label="类别:" prop="projectClass">
  16. <el-select v-model="formModel.projectClass" block clearable placeholder="请选择">
  17. <el-option v-for="item in projectClassdata" :key="item.dictValue" :label="item.dictName" :value="item.dictValue" />
  18. </el-select>
  19. </el-form-item>
  20. <el-form-item label="项目类型:" prop="projectType">
  21. <el-select v-model="formModel.projectType" block clearable placeholder="请选择">
  22. <el-option v-for="item in projectType" :key="item.dictValue" :label="item.dictName" :value="item.dictValue" />
  23. </el-select>
  24. </el-form-item>
  25. <el-form-item label="项目进程:" prop="key3">
  26. <el-select v-model="formModel.key3" block disabled="disabled" placeholder="请选择">
  27. <el-option v-for="item in projectProcess" :key="item.key" :label="item.dictName" :value="item.key" />
  28. </el-select>
  29. </el-form-item>
  30. <!-- <el-form-item label="项目进程:" prop="currentProcessName">
  31. <el-input v-model="formModel.currentProcessName" disabled/>
  32. </el-form-item> -->
  33. <el-form-item label="服务类型:" prop="projectServerType">
  34. <el-select v-model="formModel.projectServerType" block clearable placeholder="请选择">
  35. <el-option v-for="item in serverType" :key="item.dictValue" :label="item.dictName" :value="item.dictValue" />
  36. </el-select>
  37. </el-form-item>
  38. <el-form-item label="起止日期:">
  39. <HcDatePicker :dates="probetweenTime" clearable size="large" disabled="disabled" @change="betweenTimeUpdate" />
  40. </el-form-item>
  41. <el-form-item label="合同额:">
  42. <el-input v-model="formModel.contractMoney" disabled="disabled" />
  43. </el-form-item>
  44. <el-form-item label="已回款:">
  45. <el-input v-model="formModel.key7" disabled="disabled" />
  46. </el-form-item>
  47. <el-form-item label="未回款:">
  48. <el-input v-model="formModel.key7" disabled="disabled" />
  49. </el-form-item>
  50. <el-form-item label="已支出:">
  51. <el-input v-model="formModel.key7" disabled="disabled" />
  52. </el-form-item>
  53. </HcCardItem>
  54. </div>
  55. <div class="project-form-bottom">
  56. <HcCardItem title="联系人信息">
  57. <el-form-item label="项目负责人:">
  58. <el-select v-model="formModel.projectPrincipal" block clearable placeholder="请选择" size="large">
  59. <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
  60. </el-select>
  61. </el-form-item>
  62. <el-form-item label="实施负责人:">
  63. <el-select v-model="formModel.implementPrincipal" block clearable placeholder="请选择" size="large">
  64. <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
  65. </el-select>
  66. </el-form-item>
  67. <el-form-item label="维护负责人:">
  68. <el-select v-model="formModel.maintainPrincipal" block clearable placeholder="请选择" size="large">
  69. <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
  70. </el-select>
  71. </el-form-item>
  72. </HcCardItem>
  73. </div>
  74. </el-form>
  75. </el-scrollbar>
  76. </div>
  77. <div class="right-box">
  78. <el-scrollbar class="hc--right-15">
  79. <el-timeline class="p-1">
  80. <el-timeline-item v-for="(item, index) in timeLineData" :key="index" :type="item.status === 3 ? 'success' : item.status === 2 ? 'primary' : 'info'">
  81. <div class="hac-time-line-box">
  82. <div class="hac-time-line-title-box">
  83. <div class="title">
  84. {{ item.name }}
  85. </div>
  86. <div class="state">
  87. {{ item.statusValue }}
  88. </div>
  89. </div>
  90. <div class="hac-time-line-time">
  91. <span v-if="item.processStartTime" class="time">{{ `${item.processStartTime}~${item.processEndTime}` }}</span>
  92. <span v-if="dataType !== 'view'" class="icon text-blue text-hover" @click="editTime(item)">
  93. <HcIcon name="edit-2" />
  94. </span>
  95. </div>
  96. <div v-if="item.editTime" class="hac-time-line-time picker">
  97. <div class="picker-box">
  98. <HcDatePicker :dates="item.betweenTime" clearable @change="probetweenTimeUpdate($event, item)" />
  99. </div>
  100. <div class="icon-box text-blue text-hover" @click="item.editTime = false">
  101. <HcIcon name="check" />
  102. </div>
  103. </div>
  104. </div>
  105. </el-timeline-item>
  106. </el-timeline>
  107. </el-scrollbar>
  108. </div>
  109. </div>
  110. <template #action>
  111. <el-button size="large" type="info" hc-btn @click="goBackClick">
  112. <HcIcon name="arrow-go-back" />
  113. <span v-if="dataType !== 'view'">取消并返回</span>
  114. <span v-else>返回</span>
  115. </el-button>
  116. <el-button v-if="dataType !== 'view'" size="large" type="primary" hc-btn :loading="saveLoading" :disabled="saveLoading" @click="doubleClick">
  117. <HcIcon name="check-double" />
  118. <span>提交保存</span>
  119. </el-button>
  120. </template>
  121. </HcCard>
  122. </template>
  123. <script setup>
  124. import { onActivated, onMounted, ref } from 'vue'
  125. import { useRoute, useRouter } from 'vue-router'
  126. import projectApi from '~api/project/project-list.js'
  127. import { formValidate, getArrValue, getObjValue } from 'js-fast-way'
  128. import { getDictInfo, getuserList } from '~api/other'
  129. import { useAppStore } from '~src/store'
  130. const useAppState = useAppStore()
  131. const router = useRouter()
  132. const useRoutes = useRoute()
  133. //初始变量
  134. const dataType = ref(useRoutes?.query?.type ?? 'view')
  135. const dataId = ref(useRoutes?.query?.id ?? '')
  136. //缓存页面被激活时
  137. onActivated(() => {
  138. getProjectType()
  139. getProjectServerTypeDict()
  140. getprojectClassType()
  141. getProjectClass()
  142. dataType.value = useRoutes?.query?.type ?? 'view'
  143. dataId.value = useRoutes?.query?.id ?? ''
  144. getBaseProcess()
  145. getUserDict()
  146. if (dataType.value !== 'add') {
  147. getProjectInfoById()
  148. } else {
  149. formModel.value = {}
  150. probetweenTime.value = []
  151. }
  152. })
  153. onMounted(()=>{
  154. })
  155. //获取项目类型
  156. const getProjectType = async ()=>{
  157. const { error, code, data } = await projectApi.getProjectTypeDict()
  158. if (!error && code === 200) {
  159. projectType.value = getArrValue(data)
  160. } else {
  161. projectType.value = []
  162. }
  163. }
  164. //获取项目服务类型
  165. const getprojectClassType = async ()=>{
  166. const { error, code, data } = await projectApi.getProjectServerTypeDict()
  167. if (!error && code === 200) {
  168. projectClassType.value = getArrValue(data)
  169. } else {
  170. projectClassType.value = []
  171. }
  172. }
  173. //获取项目类行
  174. const getProjectServerTypeDict = async ()=>{
  175. const { error, code, data } = await projectApi.getProjectServerTypeDict()
  176. if (!error && code === 200) {
  177. serverType.value = getArrValue(data)
  178. } else {
  179. serverType.value = []
  180. }
  181. }
  182. //获取项目类别
  183. const getProjectClass = async ()=>{
  184. const { error, code, data } = await getDictInfo('project_class')
  185. if (!error && code === 200) {
  186. projectClassdata.value = getArrValue(data)
  187. } else {
  188. projectClassdata.value = []
  189. }
  190. }
  191. //获取所有员工
  192. const userList = ref([])
  193. //获取部门人员列表
  194. const getUserDict = async ()=>{
  195. const { error, code, data } = await getuserList({ tenantId:useAppState.tenantId })
  196. if (!error && code === 200) {
  197. userList.value = getArrValue(data)
  198. } else {
  199. userList.value = []
  200. }
  201. }
  202. //获取项目详情
  203. const getProjectInfoById = async ()=>{
  204. const { error, code, data } = await projectApi.getProjectInfoById({ id: dataId.value })
  205. if (!error && code === 200) {
  206. formModel.value = getObjValue(data)
  207. let arr = []
  208. arr[0] = formModel.value?.startTime
  209. arr[1] = formModel.value?.endTime
  210. probetweenTime.value = arr
  211. formModel.value.contractMoney = formModel.value.contractMoney > 0 ? formModel.value.contractMoney : ''
  212. timeLineData.value = formModel.value?.projectProcessList
  213. } else {
  214. formModel.value = {}
  215. }
  216. }
  217. //新增获取项目进程
  218. const getBaseProcess = async ()=>{
  219. const { error, code, data } = await projectApi.getBaseProcess()
  220. if (!error && code === 200) {
  221. timeLineData.value = getArrValue(data)
  222. } else {
  223. timeLineData.value = []
  224. }
  225. }
  226. //项目类型
  227. const projectType = ref([])
  228. //项目类别
  229. const projectClassdata = ref([])
  230. const projectClassType = ref([])
  231. //项目服务类型
  232. const serverType = ref([])
  233. //项目进程
  234. const projectProcess = ref([
  235. { name: '商机-演示沟通', key: '1' },
  236. { name: '商机-成本核算及报价', key: '2' },
  237. { name: '合同-服务范围洽谈', key: '3' },
  238. { name: '产品-研发', key: '4' },
  239. { name: '产品-配置', key: '5' },
  240. { name: '产品-测试', key: '6' },
  241. { name: '产品-交付', key: '7' },
  242. { name: '实施-系统培训', key: '8' },
  243. { name: '实施-现场服务', key: '9' },
  244. { name: '实施-合同回款', key: '10' },
  245. { name: '项目验收', key: '11' },
  246. ])
  247. //顶部表单数据
  248. const formRef = ref(null)
  249. const formModel = ref({
  250. key1: '', key2: '', key3: '', key4: '', key5: '',
  251. })
  252. const formRules = {
  253. name: {
  254. required: true,
  255. trigger: 'blur',
  256. message: '请输入项目名称',
  257. },
  258. projectType: {
  259. required: true,
  260. trigger: 'blur',
  261. message: '请选择项目类型',
  262. },
  263. projectClass:{
  264. required: true,
  265. trigger: 'blur',
  266. message: '请选择类别',
  267. },
  268. constructUnit: {
  269. required: true,
  270. trigger: 'blur',
  271. message: '请选择项目建设单位',
  272. },
  273. }
  274. //日期时间被选择
  275. const probetweenTime = ref(null)
  276. const betweenTimeUpdate = ({ arr, query }) => {
  277. console.log(arr, 'arr')
  278. probetweenTime.value = arr
  279. formModel.value.betweenTime = query
  280. formModel.value.startTime = arr[0]
  281. formModel.value.endTime = arr[1]
  282. console.log(formModel.value.startTime, 'sta')
  283. if (arr.length === 0) {
  284. formModel.value.startTime = ''
  285. formModel.value.endTime = ''
  286. console.log( formModel.value.endTime, 'end')
  287. }
  288. }
  289. const betweenTime = ref(null)
  290. const probetweenTimeUpdate = ({ arr }, item) => {
  291. betweenTime.value = arr
  292. item.processStartTime = arr[0]
  293. item.processEndTime = arr[1]
  294. item.betweenTime = arr
  295. }
  296. const editTime = (item)=>{
  297. item.editTime = true
  298. item.betweenTime = [item.processStartTime, item.processEndTime]
  299. }
  300. //时间线数据
  301. const timeLineData = ref([
  302. { title: '商机-沟通演示', state: '已闭环', time: '2023-02-23~2023-03-14', type: 'success' },
  303. { title: '商机-成本核算及报价', state: '已闭环', time: '2023-02-23~2023-03-14' },
  304. { title: '合同-服务范围洽谈', state: '进行中', time: '2023-02-23~2023-03-14', type: 'primary' },
  305. { title: '产品-研发', state: '未开始', time: '' },
  306. { title: '产品-配置', state: '未开始', time: '' },
  307. { title: '产品-测试', state: '未开始', time: '' },
  308. { title: '产品-交付', state: '未开始', time: '' },
  309. { title: '实施-系统培训', state: '未开始', time: '' },
  310. { title: '实施-现场服务', state: '未开始', time: '' },
  311. { title: '实施-合同回款', state: '未开始', time: '' },
  312. { title: '劳务合同', state: '未开始', time: '' },
  313. { title: '交竣工验收', state: '未开始', time: '' },
  314. ])
  315. //返回
  316. const goBackClick = () => {
  317. router.back()
  318. }
  319. const saveLoading = ref(false)
  320. //提交保存
  321. const doubleClick = async () => {
  322. saveLoading.value = true
  323. formModel.value.projectProcessList = timeLineData.value
  324. const res = await formValidate(formRef.value)
  325. if (res) {
  326. if (dataId.value.length > 0) {
  327. formModel.value.id = dataId.value
  328. updateProjectInfo()
  329. } else {
  330. addProjectInfo()
  331. }
  332. } else {
  333. saveLoading.value = false
  334. }
  335. }
  336. //新增项目
  337. const addProjectInfo = async ()=>{
  338. const { error, code, msg } = await projectApi.addProjectInfo( formModel.value)
  339. saveLoading.value = false
  340. if (!error && code === 200) {
  341. window.$message.success(msg)
  342. router.push({
  343. name: 'project',
  344. })
  345. }
  346. }
  347. //修改
  348. const updateProjectInfo = async ()=>{
  349. const { error, code, msg } = await projectApi.updateProjectInfo( formModel.value)
  350. saveLoading.value = false
  351. if (!error && code === 200) {
  352. window.$message.success(msg)
  353. router.push({
  354. name: 'project',
  355. })
  356. }
  357. }
  358. </script>
  359. <style lang="scss" scoped>
  360. .hac-card-project-box {
  361. position: relative;
  362. height: 100%;
  363. display: flex;
  364. .left-box, .right-box {
  365. flex: 1;
  366. position: relative;
  367. height: 100%;
  368. }
  369. .left-box {
  370. .project-form-top {
  371. margin-bottom: 24px;
  372. padding-right: 24px;
  373. }
  374. .project-form-bottom {
  375. padding-top: 24px;
  376. padding-right: 24px;
  377. border-top: 1px solid #e9e9e9;
  378. }
  379. }
  380. .right-box {
  381. padding-left: 24px;
  382. border-left: 1px solid #e9e9e9;
  383. .hac-time-line-box {
  384. position: relative;
  385. .hac-time-line-title-box {
  386. position: relative;
  387. display: flex;
  388. align-items: center;
  389. font-size: 16px;
  390. color: black;
  391. margin-bottom: 12px;
  392. justify-content: space-between;
  393. }
  394. .hac-time-line-time {
  395. position: relative;
  396. display: flex;
  397. align-items: center;
  398. .time {
  399. color: gray;
  400. margin-right: 8px;
  401. }
  402. .icon {
  403. font-size: 18px;
  404. }
  405. &.picker .icon-box {
  406. font-size: 20px;
  407. margin-left: 10px;
  408. }
  409. }
  410. }
  411. }
  412. }
  413. </style>
  414. <style lang="scss">
  415. </style>