Newer
Older
KaiFengPC / src / views / project / projectInformation / index.vue
@zhangdeliang zhangdeliang on 7 Nov 16 KB update
  1. <template>
  2. <!-- 项目信息 -->
  3. <div class="projectInformation">
  4. <div class="top">
  5. <el-form ref="queryFormRef" :model="form" v-show="showSearch">
  6. <el-row :gutter="20">
  7. <el-col :span="5">
  8. <el-form-item label="项目名称:" prop="projectName" class="formItem">
  9. <el-input v-model="form.projectName" placeholder="请输入项目名称" clearable style="width: 100%"></el-input>
  10. </el-form-item>
  11. </el-col>
  12. <el-col :span="4">
  13. <el-form-item label="项目类型:" prop="projectTypeId">
  14. <el-select v-model="form.projectTypeId" placeholder="请选择项目类型" style="width: 100%">
  15. <el-option label="全部" value="" />
  16. <el-option v-for="dict in projectTypes" :key="dict.id" :label="dict.projectTypeName" :value="dict.id" />
  17. </el-select>
  18. </el-form-item>
  19. </el-col>
  20. <el-col :span="4">
  21. <el-form-item label="建设类别:" prop="buildCategory">
  22. <el-select v-model="form.buildCategory" placeholder="请选择建设类别" style="width: 100%">
  23. <el-option label="全部" value="" />
  24. <el-option v-for="dict in build_category" :key="dict.value" :label="dict.label" :value="dict.value" />
  25. </el-select>
  26. </el-form-item>
  27. </el-col>
  28. <el-col :span="6.5">
  29. <el-form-item label="项目日期:" prop="time">
  30. <el-date-picker
  31. v-model="form.time"
  32. type="daterange"
  33. range-separator="-"
  34. start-placeholder="开始日期"
  35. end-placeholder="结束日期"
  36. value-format="YYYY-MM-DD"
  37. />
  38. </el-form-item>
  39. </el-col>
  40. <el-col :span="4.5">
  41. <el-form-item label="责任部门:" prop="chargeDepartment">
  42. <el-input v-model="form.chargeDepartment" placeholder="请输入责任部门" style="width: 100%"></el-input>
  43. </el-form-item>
  44. </el-col>
  45. </el-row>
  46. <el-row :gutter="20">
  47. <el-col :span="5">
  48. <el-form-item label="项目库类型:" prop="projectLibraryType" class="formItem">
  49. <el-select v-model="form.projectLibraryType" placeholder="请选择项目库类型" style="width: 100%">
  50. <el-option label="全部" value="" />
  51. <el-option v-for="dict in project_library_type" :key="dict.value" :label="dict.label" :value="dict.value" />
  52. </el-select>
  53. </el-form-item>
  54. </el-col>
  55. <el-col :span="4.5">
  56. <el-form-item>
  57. <el-button type="primary" icon="Search" @click="search"> 搜索</el-button>
  58. <el-button icon="Refresh" @click="resetQuery">重置</el-button>
  59. </el-form-item>
  60. </el-col>
  61. </el-row>
  62. </el-form>
  63. </div>
  64.  
  65. <card-list class="card-list" ref="cardListRef" />
  66.  
  67. <el-row class="row">
  68. <el-button type="primary" plain icon="Plus" @click="openDialog({}, 'add')">新增项目</el-button>
  69. <el-button type="danger" plain icon="Delete" @click="batchDel">批量删除</el-button>
  70. <el-button type="primary" plain icon="Edit" @click="editSchedule">修改进度</el-button>
  71. <el-button type="primary" plain icon="Download" @click="Download">导出</el-button>
  72. <right-toolbar v-model:showSearch="showSearch" @queryTable="resetQuery"></right-toolbar>
  73. </el-row>
  74. <div class="table" ref="table_box">
  75. <el-table :data="tableData" v-loading="loading" stripe :max-height="430" ref="multipleTableRef">
  76. <el-table-column type="selection" width="55" />
  77. <el-table-column label="项目名称" prop="projectName" show-overflow-tooltip />
  78. <el-table-column label="项目编码" prop="projectNo" width="80" />
  79. <el-table-column label="数据来源" prop="projectSource" width="120">
  80. <template #default="{ row }">
  81. <dict-tag :options="project_data_sources" :value="row.projectSource" />
  82. </template>
  83. </el-table-column>
  84. <el-table-column label="建设类别" prop="buildCategory" width="80">
  85. <template #default="{ row }">
  86. <span>{{ findText('build_category', row.buildCategory) }}</span>
  87. </template>
  88. </el-table-column>
  89. <el-table-column label="是否豁免" prop="isProjectExempt" width="80">
  90. <template #default="{ row }">
  91. <span>{{ row.isProjectExempt == '1' ? '是' : '否' }}</span>
  92. </template>
  93. </el-table-column>
  94. <el-table-column label="项目库类型" prop="projectLibraryType" width="90">
  95. <template #default="{ row }">
  96. <span>{{ findText('project_library_type', row.projectLibraryType) }}</span>
  97. </template>
  98. </el-table-column>
  99. <el-table-column label="建设进度" prop="projectProgress" width="80" />
  100. <el-table-column label="项目起止日期" prop="projectTime" width="140" />
  101. <el-table-column label="填报时间" prop="createTime" width="160" />
  102. <el-table-column label="项目概况" prop="projectOverview" show-overflow-tooltip />
  103. <el-table-column label="操作" show-overflow-tooltip width="240">
  104. <template #default="{ row }">
  105. <el-button icon="View" type="primary" link @click="openDialog(row, 'view')">详情</el-button>
  106. <el-button type="warning" icon="Edit" link @click="openDialog(row, 'edit')">修改</el-button>
  107. <el-button type="danger" icon="Delete" link @click="del(row)">删除</el-button>
  108. </template>
  109. </el-table-column>
  110. </el-table>
  111. <pagination class="pagination" :total="total" v-model:page="pageNum" v-model:limit="pageSize" @pagination="getTableList" />
  112. </div>
  113. <el-dialog
  114. v-model="visible"
  115. :title="`${opts.text}项目`"
  116. :close-on-click-modal="false"
  117. style="height: 800px"
  118. width="70%"
  119. :before-close="close"
  120. >
  121. <operate
  122. ref="operateRef"
  123. v-if="['add', 'edit'].includes(opts.type)"
  124. :cur-row="curRow"
  125. :opts="opts"
  126. :types="projectTypes"
  127. :build-category="build_category"
  128. :project-library-type="project_library_type"
  129. :project-content-type="project_content_type"
  130. @close="close"
  131. />
  132. <detail
  133. :cur-row="curRow"
  134. :types="projectTypes"
  135. :build-category="build_category"
  136. :project-library-type="project_library_type"
  137. :project-content-type="project_content_type"
  138. v-else-if="opts.type === 'view'"
  139. />
  140. <template #footer v-if="opts.type !== 'view'">
  141. <div class="dialog-footer">
  142. <el-button type="primary" @click="handleOk">确 定</el-button>
  143. <el-button @click="close">取 消</el-button>
  144. </div>
  145. </template>
  146. </el-dialog>
  147. <el-dialog v-model="visible1" title="修改建设进度" :close-on-click-modal="false" width="40%" :before-close="dialogClose" class="dialog">
  148. <el-form ref="dialogRuleFormRef" :model="dialogForm" :rules="dialogRules" v-if="visible1">
  149. <el-form-item label="建设状态:" prop="buildStatus">
  150. <el-select v-model="dialogForm.buildStatus" placeholder="请选择建设状态" style="width: 100%">
  151. <el-option v-for="dict in build_status" :key="dict.value" :label="dict.label" :value="dict.value" />
  152. </el-select>
  153. </el-form-item>
  154. <el-form-item label="建设进度:" prop="projectProgress">
  155. <div style="display: flex; width: 100%">
  156. <el-slider v-model="dialogForm.projectProgress" style="flex: 1" />
  157. <span style="margin-left: 10px">{{ dialogForm.projectProgress + '%' }}</span>
  158. </div>
  159. </el-form-item>
  160. <el-form-item label="完成项目总投资(含主体工程)(万元):" prop="accomplishTotalInvest">
  161. <el-input v-model="dialogForm.accomplishTotalInvest" placeholder="请输入完成项目总投资" />
  162. </el-form-item>
  163. <el-form-item label="完成海绵相关投资(不含主体工程)(万元):" prop="accomplishSpongeInvest">
  164. <el-input v-model="dialogForm.accomplishSpongeInvest" placeholder="请输入完成海绵相关投资" />
  165. </el-form-item>
  166. <el-form-item label="建设过程中照片:" prop="underWay">
  167. <div class="upload">
  168. <ImageFileUpload
  169. listType="picture-card"
  170. :limit="10"
  171. :saveFileArr="constractionFlieList"
  172. refType="projectInfoNew"
  173. refField="constraction"
  174. :fileType="['png', 'jpg', 'jpeg']"
  175. />
  176. </div>
  177. </el-form-item>
  178. <el-form-item label="建设完成后照片:" prop="complete">
  179. <div class="upload">
  180. <ImageFileUpload
  181. listType="picture-card"
  182. :limit="10"
  183. :saveFileArr="postConstractionFlieList"
  184. refType="projectInfoNew"
  185. refField="postConstraction"
  186. :fileType="['png', 'jpg', 'jpeg']"
  187. />
  188. </div>
  189. </el-form-item>
  190. </el-form>
  191. <template #footer v-if="opts.type !== 'view'">
  192. <div class="dialog-footer">
  193. <el-button type="primary" @click="dialogSubmit">确 定</el-button>
  194. <el-button @click="dialogClose">取 消</el-button>
  195. </div>
  196. </template>
  197. </el-dialog>
  198. <el-dialog v-model="visible2" title="查看位置" :close-on-click-modal="false" width="800px">
  199. <MapPosition v-if="showMap" :isShowSearch="false" :isShowTool="false"></MapPosition>
  200. </el-dialog>
  201. </div>
  202. </template>
  203.  
  204. <script setup>
  205. import { usePagination, useAdaption, useDicts } from '@/hooks';
  206. import CardList from './components/cardList.vue';
  207. import { optTextMap } from '@/utils/map';
  208. import operate from './operate.vue';
  209. import detail from './details.vue';
  210. import MapPosition from '@/components/Map/index.vue'; //地图选点获取经纬度位置组件
  211. import { required } from '@/utils/validate-helper';
  212. import { inheritAttr } from '@/utils/v3';
  213. import {
  214. getProjectInfoNewPage,
  215. projectTypeList,
  216. projectInfoNewDel,
  217. projectInfoNewDetail,
  218. updateProjectBuildStatus,
  219. } from '@/api/project/projectInformationNew';
  220. import bus from '@/bus';
  221. const { proxy } = getCurrentInstance();
  222. const { build_category, project_library_type, project_content_type, build_status, findText } = useDicts(proxy);
  223. const { project_data_sources } = proxy.useDict('project_data_sources');
  224. const showSearch = ref(true);
  225. const form = reactive({
  226. projectName: '',
  227. projectTypeId: '',
  228. buildCategory: '',
  229. time: '',
  230. chargeDepartment: '',
  231. projectLibraryType: '',
  232. });
  233.  
  234. const params = computed(() => {
  235. const args = JSON.parse(JSON.stringify(form));
  236. const { time } = args;
  237. delete args.time;
  238. return {
  239. ...args,
  240. startTime: time?.[0] || '',
  241. endTime: time?.[1] || '',
  242. };
  243. });
  244.  
  245. const dialogForm = reactive({
  246. projectNo: '',
  247. buildStatus: '',
  248. projectProgress: 0,
  249. accomplishTotalInvest: '',
  250. accomplishSpongeInvest: '',
  251. underWay: '',
  252. complete: '',
  253. });
  254.  
  255. const dialogRules = reactive({
  256. buildStatus: required('建设状态'),
  257. projectProgress: required('建设进度'),
  258. accomplishTotalInvest: required('完成项目总投资'),
  259. accomplishSpongeInvest: required('完成海绵相关投资'),
  260. });
  261.  
  262. const constractionFlieList = ref([]);
  263. const postConstractionFlieList = ref([]);
  264. const opts = reactive({
  265. type: '',
  266. text: '',
  267. });
  268. const visible = ref(false);
  269. const curRow = shallowRef({});
  270. const visible1 = ref(false);
  271. const checkedList = shallowRef([]);
  272. const projectTypes = ref([]);
  273. const visible2 = ref(false);
  274. const { pageNum, pageSize, tableData, total, loading, getTableList } = usePagination(getProjectInfoNewPage, params);
  275.  
  276. const getProjectTypeList = async () => {
  277. const res = await projectTypeList({ status: '0' });
  278. if (res?.code !== 200) return;
  279. projectTypes.value = res?.data || [];
  280. };
  281.  
  282. const search = () => {
  283. pageNum.value = 1;
  284. getTableList();
  285. };
  286. const resetQuery = () => {
  287. proxy.$refs.queryFormRef.resetFields();
  288. search();
  289. };
  290.  
  291. const openDialog = (data, type) => {
  292. visible.value = true;
  293. opts.type = type;
  294. opts.text = optTextMap.get(type);
  295. curRow.value = data;
  296. curRow.value.analysisUsers1 = data.drainagePartition ? data.drainagePartition.split(',') : [];
  297. };
  298.  
  299. const close = type => {
  300. visible.value = false;
  301. opts.type = '';
  302. opts.text = '';
  303. if (['edit', 'add'].includes(type)) {
  304. search();
  305. proxy.$refs.cardListRef.getData();
  306. }
  307. };
  308.  
  309. const del = row => {
  310. proxy.$modal
  311. .confirm('是否确认删除?')
  312. .then(async () => {
  313. const res = await projectInfoNewDel(row.id);
  314. if (res?.code !== 200) return;
  315. proxy.$modal.msgSuccess('操作成功!');
  316. getTableList();
  317. proxy.$refs.cardListRef.getData();
  318. })
  319. .catch(() => {});
  320. };
  321.  
  322. const editSchedule = async () => {
  323. const list = proxy.$refs.multipleTableRef.getSelectionRows();
  324. if (!list.length) return proxy.$modal.msgError('请选择一条数据!');
  325. if (list.length > 1) return proxy.$modal.msgError('只能选择一条数据!');
  326. visible1.value = true;
  327. checkedList.value = list;
  328. const res = await projectInfoNewDetail(list[0].projectNo);
  329. if (res?.code !== 200) return;
  330. console.log(res.data);
  331. inheritAttr(res.data, dialogForm);
  332.  
  333. res.data.sysFileList = res.data.sysFileList || [];
  334. for (const item of res.data.sysFileList) {
  335. item.refType = 'projectInfoNew';
  336. }
  337. constractionFlieList.value = res.data.sysFileList.filter(item => item.refField === 'constraction');
  338. postConstractionFlieList.value = res.data.sysFileList.filter(item => item.refField === 'postConstraction');
  339. };
  340.  
  341. const batchDel = () => {
  342. const checkedList = proxy.$refs.multipleTableRef.getSelectionRows();
  343. if (!checkedList.length) return proxy.$modal.msgError('请选择一条数据!');
  344. proxy.$modal
  345. .confirm('是否确认删除?')
  346. .then(async () => {
  347. const res = await projectInfoNewDel(checkedList.map(item => item.id).join());
  348. if (res?.code !== 200) return;
  349. proxy.$modal.msgSuccess('操作成功!');
  350. getTableList();
  351. proxy.$refs.cardListRef.getData();
  352. })
  353. .catch(() => {});
  354. };
  355.  
  356. const handleOk = () => {
  357. proxy.$refs.operateRef.submit();
  358. };
  359.  
  360. const dialogClose = () => {
  361. visible1.value = false;
  362. checkedList.value = [];
  363. };
  364.  
  365. const dialogSubmit = () => {
  366. proxy.$refs.dialogRuleFormRef.validate(async (valid, fields) => {
  367. if (valid) {
  368. console.log('submit!', dialogForm);
  369. const sysFileSaveRequestList = [].concat(constractionFlieList.value, postConstractionFlieList.value);
  370. const res = await updateProjectBuildStatus({ projectNo: checkedList.value[0].projectNo, ...dialogForm, sysFileSaveRequestList });
  371. if (res?.code !== 200) return;
  372. proxy.$modal.msgSuccess('操作成功!');
  373. getTableList();
  374. dialogClose();
  375. } else {
  376. console.log('error submit!', fields);
  377. }
  378. });
  379. };
  380.  
  381. //导出
  382. function Download() {
  383. proxy.$modal
  384. .confirm('是否确认导出?')
  385. .then(async () => {
  386. proxy.download('/business/projectInfoNew/export', {}, `项目信息${new Date().getTime()}.xlsx`);
  387. })
  388. .catch(() => {});
  389. }
  390.  
  391. onMounted(() => {
  392. getTableList();
  393. getProjectTypeList();
  394. });
  395. </script>
  396.  
  397. <style lang="scss" scoped>
  398. .projectInformation {
  399. padding: 20px;
  400. height: 90vh;
  401. display: flex;
  402. flex-direction: column;
  403. .top {
  404. // margin-bottom: 15px;
  405. flex-shrink: 0;
  406. }
  407. .card-list {
  408. flex-shrink: 0;
  409. }
  410. .table {
  411. flex: 1;
  412. :deep(.pagination) {
  413. margin-top: 0;
  414. margin-right: 10px;
  415. .el-pagination {
  416. right: 20px;
  417. }
  418. }
  419. }
  420. :deep(.formItem) {
  421. .el-form-item__label {
  422. width: 110px;
  423. word-break: keep-all;
  424. }
  425. }
  426. }
  427.  
  428. .row {
  429. margin: 10px 0;
  430. }
  431.  
  432. .upload {
  433. position: relative;
  434. .fileName {
  435. position: absolute;
  436. left: 0;
  437. top: 30px;
  438. white-space: nowrap;
  439. display: flex;
  440. align-items: center;
  441. .del {
  442. flex-shrink: 0;
  443. color: #f56c6c;
  444. cursor: pointer;
  445. margin-left: 10px;
  446. }
  447. }
  448.  
  449. .imgBox {
  450. display: flex;
  451. flex-wrap: wrap;
  452. .img {
  453. margin-right: 10px;
  454. }
  455. }
  456. }
  457.  
  458. .img {
  459. position: relative;
  460. width: 178px;
  461. height: 178px;
  462. img {
  463. width: 100%;
  464. height: 100%;
  465. }
  466. .mask {
  467. position: absolute;
  468. left: 0;
  469. right: 0;
  470. top: 0;
  471. bottom: 0;
  472. background-color: rgba(0, 0, 0, 0.5);
  473. display: none;
  474. .icon {
  475. position: absolute;
  476. left: 50%;
  477. top: 50%;
  478. transform: translate(-50%, -50%);
  479. color: #fff;
  480. }
  481. }
  482. &:hover {
  483. .mask {
  484. display: block;
  485. }
  486. }
  487. }
  488. </style>