apply-form.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. <template>
  2. <div>
  3. <div v-if="operateType === 'edit'" class="tool-btn" style="width: 800px; margin: 0 auto; text-align: right;">
  4. <!-- <el-button size="small" type="primary" plain @click="handleExportWord">导出word</el-button> -->
  5. <el-button size="small" type="primary" icon="el-icon-printer" v-print="printConfig" @click="isPrintPage = true">打印</el-button>
  6. </div>
  7. <div id="applyDoc" class="apply-form" v-loading="loading">
  8. <h3 class="page-title" style="height: 60px; line-height: 60px; margin: 0;">{{ teantData.tenantName }}</h3>
  9. <h3 class="page-title" style="margin: 5px 0 16px;">{{ getDocTile }}</h3>
  10. <div class="project-basic-info">
  11. <div class="info-row">{{ `研发项目名称:${ formData.xmmc || '' }` }}</div>
  12. <div class="info-row">{{ `项目负责人:${ getXmfzrName || '' }` }}</div>
  13. <div class="info-row">{{ `项目申请单位:${ xmsqdwName }` }}</div>
  14. <div class="info-row">{{ `项目执行期:${ getXmDateRange || '' }` }}</div>
  15. </div>
  16. <!-- 打印强制分页 -->
  17. <div style="page-break-after: always;"></div>
  18. <h3 class="page-title" style="margin: 24px 0 16px;">研发立项申请表</h3>
  19. <table>
  20. <tbody>
  21. <tr>
  22. <td class="doc-label">
  23. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>研发项目名称
  24. </td>
  25. <td class="doc-input">
  26. <el-input v-if="!isPrintPage" v-model="formData.xmmc" placeholder="请输入项目名称" :disabled="isDisabled" />
  27. <span v-else style="display: inline-block; padding: 12px 6px;">{{ formData.xmmc }}</span>
  28. </td>
  29. <td class="doc-label">
  30. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>项目编号
  31. </td>
  32. <td class="doc-input">
  33. <el-input v-if="!isPrintPage" v-model="formData.xmbh" placeholder="请输入项目编号" :disabled="isDisabled" />
  34. <span v-else style="display: inline-block; padding: 12px 6px;">{{ formData.xmbh }}</span>
  35. </td>
  36. </tr>
  37. <tr>
  38. <td class="doc-label">
  39. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>研发开始时间
  40. </td>
  41. <td class="doc-input">
  42. <el-date-picker
  43. v-if="!isPrintPage"
  44. v-model="formData.xmkssj"
  45. format="yyyy年MM月dd日"
  46. value-format="yyyy-MM-dd"
  47. placeholder="请选择日期"
  48. style="width: 100%"
  49. :disabled="isDisabled"
  50. ></el-date-picker>
  51. <span v-else style="display: inline-block; padding: 12px 6px;">{{ formData.xmkssj }}</span>
  52. </td>
  53. <td class="doc-label">
  54. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>研发结束时间
  55. </td>
  56. <td class="doc-input">
  57. <el-date-picker
  58. v-if="!isPrintPage"
  59. v-model="formData.xmjssj"
  60. format="yyyy年MM月dd日"
  61. value-format="yyyy-MM-dd"
  62. placeholder="请选择日期"
  63. style="width: 100%"
  64. :disabled="isDisabled"
  65. ></el-date-picker>
  66. <span v-else style="display: inline-block; padding: 12px 6px;">{{ formData.xmjssj }}</span>
  67. </td>
  68. </tr>
  69. <tr>
  70. <td class="doc-label">
  71. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>项目申请单位
  72. </td>
  73. <td colspan="3">
  74. <second-unit-cascader
  75. v-show="!isPrintPage"
  76. ref="secondUnitCascader"
  77. v-model="formData.xmsqdwid"
  78. :yearAndMonth="yearAndMonth"
  79. style="width: 100%;"
  80. :disabled="isDisabled"
  81. @change="handleSecondUnitChange"
  82. >
  83. </second-unit-cascader>
  84. <span v-show="isPrintPage" style="display: inline-block; padding: 12px; color: #333;">{{ xmsqdwName }}</span>
  85. </td>
  86. </tr>
  87. <tr>
  88. <td class="doc-label">
  89. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>项目负责人
  90. </td>
  91. <td class="doc-input">
  92. <person-select v-show="!isPrintPage" v-model="formData.xmfzr" :yearAndMonth="xmStartDateYearAndMonth" valueKey="id" :disabled="isDisabled" style="width: 100%" />
  93. <span v-show="isPrintPage" style="display: inline-block; padding: 12px 6px;">{{ getXmfzrName }}</span>
  94. </td>
  95. <td class="doc-label">
  96. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>研究类型
  97. </td>
  98. <td class="doc-input">
  99. <avue-select
  100. v-if="!isPrintPage"
  101. v-model="formData.yjlx"
  102. placeholder="请选择"
  103. :dic="studyTypeList"
  104. style="width: 100%"
  105. :disabled="projectIsSucc"
  106. ></avue-select>
  107. <span v-else style="display: inline-block; padding: 12px;">{{ formData.yjlx }}</span>
  108. </td>
  109. </tr>
  110. <tr>
  111. <td class="doc-label">
  112. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>项目来源
  113. </td>
  114. <td class="doc-input">
  115. <avue-select
  116. v-if="!isPrintPage"
  117. v-model="formData.xmly"
  118. placeholder="请选择"
  119. :dic="projectSourceList"
  120. style="width: 100%"
  121. :disabled="projectIsSucc"
  122. ></avue-select>
  123. <span v-else style="display: inline-block; padding: 12px;">{{ formData.xmly }}</span>
  124. </td>
  125. <td class="doc-label">
  126. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>项目开展形式
  127. </td>
  128. <td class="doc-input">
  129. <avue-select
  130. v-if="!isPrintPage"
  131. v-model="formData.xmkzxs"
  132. placeholder="请选择"
  133. :dic="implementFormatList"
  134. style="width: 100%"
  135. :disabled="projectIsSucc"
  136. ></avue-select>
  137. <span v-else style="display: inline-block; padding: 12px;">{{ formData.xmkzxs }}</span>
  138. </td>
  139. </tr>
  140. <tr>
  141. <td class="doc-label">
  142. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>预期成果形式
  143. </td>
  144. <td class="doc-input">
  145. <avue-select
  146. v-if="!isPrintPage"
  147. multiple
  148. v-model="formData.yqcgxs"
  149. placeholder="请选择"
  150. :dic="expectedOutComeFormList"
  151. style="width: 100%"
  152. :disabled="projectIsSucc"
  153. ></avue-select>
  154. <template v-else>
  155. <div style="padding: 12px;">
  156. <div v-for="(item, index) of formData.yqcgxs" :key="index">{{ item }}</div>
  157. </div>
  158. </template>
  159. </td>
  160. <td class="doc-label">
  161. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>项目技术经济目标
  162. </td>
  163. <td class="doc-input">
  164. <avue-select
  165. v-if="!isPrintPage"
  166. multiple
  167. v-model="formData.xmjsjjmb"
  168. placeholder="请选择"
  169. :dic="economicObjectivesList"
  170. style="width: 100%"
  171. :disabled="projectIsSucc"
  172. ></avue-select>
  173. <template v-else>
  174. <div style="padding: 12px;">
  175. <div v-for="(item, index) of formData.xmjsjjmb" :key="index">{{ item }}</div>
  176. </div>
  177. </template>
  178. </td>
  179. </tr>
  180. <tr>
  181. <td class="doc-label">
  182. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>项目预算总额(万元)
  183. </td>
  184. <td class="doc-input">
  185. <!-- <el-input-number v-model="formData.xmysze" type="number" :min="0" controls-position="right" :disabled="isDisabled" /> -->
  186. {{ getXmysze }}
  187. </td>
  188. <td class="doc-label">
  189. <span v-if="!isPrintPage" style="color: red; padding-right: 3px; font-size: 16px;">*</span>其中
  190. </td>
  191. <td class="doc-input">
  192. <div class="year-list">
  193. <div class="year-list-item" v-for="year of yearList" :key="year" :style="{ height: yearList.length == 1 ? '51px' : '32px', lineHeight: yearList.length == 1 ? '51px' : '32px' }">
  194. <div class="year" >{{ year }}</div>
  195. <div class="year-input">
  196. <input v-if="!isPrintPage" v-model="formData[year]" type="number" @input="handleYearInput" style="padding: 0 6px;" :disabled="isDisabled" />
  197. <span v-else style="padding-left: 12px;">{{ formData[year] }}万元</span>
  198. </div>
  199. </div>
  200. </div>
  201. </td>
  202. </tr>
  203. </tbody>
  204. </table>
  205. <avue-form v-show="!isPrintPage" v-model="formData" :option="option" style="margin-top: 30px; padding: 0;">
  206. <template slot="lxpwLabel">
  207. <label>立项批文</label>
  208. <div style="position: absolute; top: 0; left: 220px; z-index: 1;">
  209. <file-download-btn templateKey="研发项目管理-项目立项-立项批文"></file-download-btn>
  210. </div>
  211. </template>
  212. <template slot="lxbgLabel">
  213. <label>立项报告</label>
  214. <div style="position: absolute; top: 0; left: 220px; z-index: 1;">
  215. <file-download-btn templateKey="研发项目管理-项目立项-立项报告"></file-download-btn>
  216. </div>
  217. </template>
  218. <template slot="qtzlLabel">
  219. <label>其他资料</label>
  220. <div style="position: absolute; top: 0; left: 220px; z-index: 1;">
  221. <file-download-btn templateKey="研发项目管理-项目立项-其他资料"></file-download-btn>
  222. </div>
  223. </template>
  224. </avue-form>
  225. <div v-show="isPrintPage" class="file-list" style="margin-top: 30px;">
  226. <div class="file-list-item" style="display: flex; margin-bottom: 18px;">
  227. <div class="name">立项批文:</div>
  228. <div class="file-wrap">
  229. <div v-for="(item, idx) of formData.lxpw" :key="idx">{{ item.label }}</div>
  230. </div>
  231. </div>
  232. <div class="file-list-item" style="display: flex; margin-bottom: 18px;">
  233. <div class="name">立项报告:</div>
  234. <div class="file-wrap">
  235. <div v-for="(item, idx) of formData.lxbg" :key="idx">{{ item.label }}</div>
  236. </div>
  237. </div>
  238. <div class="file-list-item" style="display: flex;">
  239. <div class="name">其他资料:</div>
  240. <div class="file-wrap">
  241. <div v-for="(item, idx) of formData.qtzl" :key="idx">{{ item.label }}</div>
  242. </div>
  243. </div>
  244. </div>
  245. <p v-if="!isPrintPage" class="tip">注:可一次上传多个相关文件(文档、表格、图片等)。 支持格式:DOC, PDF, Excel, PNG, JPG, PPT 等。 请确保文件内容清晰有效。</p>
  246. <div v-if="!projectIsSucc" class="btn-wrap printHide" style="text-align: center;">
  247. <template v-if="operateType == 'add' || projectId && formData.status == 0">
  248. <el-button type="primary" style="width: 160px;" @click="handleSaveBtn(0)">暂存</el-button>
  249. <el-button type="primary" style="width: 160px;" @click="handleSaveBtn(1)">确定立项</el-button>
  250. </template>
  251. <el-button v-else-if="projectId && formData.status != 0" type="primary" style="width: 160px;" @click="handleSaveBtn()">保存</el-button>
  252. </div>
  253. </div>
  254. </div>
  255. </template>
  256. <script>
  257. import secondUnitCascader from "@/components/second-unit-cascader";
  258. import personSelect from "@/components/person-select";
  259. import fileDownloadBtn from "@/components/file-download-btn";
  260. import { getDictionary } from "@/api/system/dictbiz";
  261. import { save, update, getApprove } from "@/api/projectManage/projectList";
  262. import moment from "moment";
  263. import { deepClone } from "@/util/util";
  264. import Decimal from "decimal.js";
  265. import { mapGetters } from "vuex";
  266. import { getDetail as getTenantDetail } from '@/api/system/tenant';
  267. import { downloadFileByUrl } from "@/util/util";
  268. import { exportBlob } from "@/api/common";
  269. import { getToken } from "@/util/auth";
  270. import { downloadXls } from "@/util/util";
  271. export default {
  272. components: {
  273. personSelect,
  274. secondUnitCascader,
  275. fileDownloadBtn
  276. },
  277. props: {
  278. // add or edit
  279. operateType: {
  280. type: String,
  281. default: 'add'
  282. },
  283. projectId: [String, Number]
  284. },
  285. data() {
  286. return {
  287. loading: false,
  288. formData: {
  289. xmmc: '',
  290. xmbh: '',
  291. xmkssj: '',
  292. xmjssj: '',
  293. xmsqdwid: [],
  294. xmfzr: '',
  295. yjlx: '',
  296. xmly: '',
  297. xmkzxs: '',
  298. yqcgxs: [],
  299. xmjsjjmb: [],
  300. lxpw: [],
  301. lxbg: [],
  302. qtzl: []
  303. },
  304. yearList: [],
  305. // 预算是否超出
  306. budgetIsExceed: false,
  307. // 项目负责人列表
  308. fzrList: [],
  309. // 研究类型数据字典
  310. studyTypeList: [],
  311. // 项目来源列表
  312. projectSourceList: [],
  313. // 开展形式
  314. implementFormatList: [],
  315. // 预期成果形式
  316. expectedOutComeFormList: [],
  317. // 经济目标
  318. economicObjectivesList: [],
  319. xmsqdwName: '',
  320. // 租户信息
  321. teantData: {},
  322. isPrintPage: false,
  323. printConfig: {
  324. el: '#applyDoc', //被打印部分的id
  325. closeCallback: () => {
  326. this.isPrintPage = false;
  327. }
  328. },
  329. };
  330. },
  331. watch: {
  332. 'formData.xmkssj'(newVal) {
  333. this.yearList = this.getDateRangeYear(newVal, this.formData.xmjssj);
  334. let cMonth = newVal ? moment(newVal).format('yyyyMM') : '';
  335. if (cMonth != this.xmStartDateYearAndMonth) {
  336. this.xmStartDateYearAndMonth = cMonth;
  337. }
  338. },
  339. 'formData.xmjssj'(newVal) {
  340. this.yearList = this.getDateRangeYear(this.formData.xmkssj, newVal);
  341. },
  342. 'formData.xmysze'(newVal) {
  343. this.calcBudgetIsExceed(newVal);
  344. },
  345. },
  346. computed: {
  347. ...mapGetters(["userInfo"]),
  348. isDisabled() {
  349. return this.operateType == 'edit' && this.formData.status != 0;
  350. },
  351. // 项目是否已结题
  352. projectIsSucc() {
  353. return this.formData.status == 2;
  354. },
  355. // 获取项目预算总额
  356. getXmysze() {
  357. let total = new Decimal(0);
  358. this.yearList.forEach(year => {
  359. total = total.add (new Decimal(this.formData[year] || 0));
  360. });
  361. return total.toFixed(2);
  362. },
  363. option() {
  364. return {
  365. submitBtn: false,
  366. emptyBtn: false,
  367. submitText: '保存',
  368. menuBtn: false,
  369. column: [
  370. {
  371. label: "立项批文",
  372. prop: "lxpw",
  373. type: "upload",
  374. multiple: true,
  375. span: 24,
  376. disabled: this.projectIsSucc,
  377. dataType: "object",
  378. propsHttp: {
  379. url: "link",
  380. name: "originalName",
  381. res: "data",
  382. },
  383. action: '/api/kd-resource/oss/endpoint/put-file',
  384. uploadPreview: (file, column, done) => {
  385. downloadFileByUrl(file.url, file.name);
  386. return;
  387. },
  388. // rules: [{
  389. // required: true,
  390. // message: "请上传立项批文"
  391. // }]
  392. },
  393. {
  394. label: "立项报告",
  395. prop: "lxbg",
  396. type: "upload",
  397. multiple: true,
  398. span: 24,
  399. dataType: "object",
  400. propsHttp: {
  401. url: "link",
  402. name: "originalName",
  403. res: "data",
  404. },
  405. action: '/api/kd-resource/oss/endpoint/put-file',
  406. disabled: this.projectIsSucc,
  407. uploadPreview: (file, column, done) => {
  408. downloadFileByUrl(file.url, file.name);
  409. return;
  410. },
  411. // rules: [{
  412. // required: true,
  413. // message: "请上传立项报告"
  414. // }]
  415. },
  416. {
  417. label: "其他资料",
  418. prop: "qtzl",
  419. type: "upload",
  420. multiple: true,
  421. span: 24,
  422. action: '/api/kd-resource/oss/endpoint/put-file',
  423. disabled: this.projectIsSucc,
  424. uploadPreview: (file, column, done) => {
  425. downloadFileByUrl(file.url, file.name);
  426. return;
  427. },
  428. dataType: "object",
  429. propsHttp: {
  430. url: "link",
  431. name: "originalName",
  432. res: "data",
  433. },
  434. },
  435. ],
  436. }
  437. },
  438. getDocTile() {
  439. let tit = '研发项目资料';
  440. if (this.formData.xmmc) {
  441. return `${this.formData.xmmc}${tit}`;
  442. }
  443. return tit;
  444. },
  445. getXmfzrName() {
  446. // if (this.formData.xmfzr) {
  447. // let fzrObj = this.fzrList.find(item => item.value == this.formData.xmfzr);
  448. // return fzrObj ? fzrObj.label : "";
  449. // }
  450. return this.formData.xmfzrxm;
  451. },
  452. getXmDateRange() {
  453. if (this.formData.xmkssj && this.formData.xmjssj) {
  454. let xmkssj = moment(this.formData.xmkssj).format('yyyy年MM月DD日');
  455. let xmjssj = moment(this.formData.xmjssj).format('yyyy年MM月DD日')
  456. return `${xmkssj}至${xmjssj}`;
  457. }
  458. return `年 月 日至 年 月 日`;
  459. },
  460. yearAndMonth() {
  461. return !!this.formData.xmkssj ? moment(this.formData.xmkssj).format('yyyy') : '';
  462. }
  463. },
  464. mounted() {
  465. this.getTenantDetailFunc(this.userInfo.tenant_id);
  466. this.getDictList("study_type", "studyTypeList");
  467. this.getDictList("project_source", "projectSourceList");
  468. this.getDictList("implementation_format", "implementFormatList");
  469. this.getDictList("expected_outcome_form", "expectedOutComeFormList");
  470. this.getDictList("economic_objectives", "economicObjectivesList");
  471. if (this.projectId) {
  472. this.getProjectDetail(this.projectId);
  473. }
  474. },
  475. methods: {
  476. // 获取租户详情信息
  477. getTenantDetailFunc(tenantId) {
  478. getTenantDetail(tenantId).then(({ data }) => {
  479. if (data.code == 200) {
  480. this.teantData = data.data;
  481. }
  482. });
  483. },
  484. handleSecondUnitChange(val, nameArr) {
  485. this.xmsqdwName = nameArr.join('/');
  486. },
  487. getProjectDetail(xmId) {
  488. this.loading = true;
  489. getApprove({ xmId }).then(({ data }) => {
  490. this.loading = false;
  491. if (data.code == 200) {
  492. let beanData = { ...data.data };
  493. beanData.xmfzr = beanData.xmfzr.toString();
  494. beanData.yqcgxs = beanData.yqcgxs.split(",");
  495. beanData.xmjsjjmb = beanData.xmjsjjmb.split(",");
  496. beanData.lxpw = beanData.lxpw ? JSON.parse(beanData.lxpw) : [];
  497. beanData.lxbg = beanData.lxbg ? JSON.parse(beanData.lxbg) : [];
  498. beanData.qtzl = beanData.qtzl ? JSON.parse(beanData.qtzl) : [];
  499. beanData.xmyszemx = beanData.xmyszemx ? JSON.parse(beanData.xmyszemx) : [];
  500. beanData.xmyszemx.forEach(item => {
  501. beanData[item.year] = item.amount;
  502. });
  503. this.formData = { ...beanData };
  504. }
  505. }).catch(err => {
  506. this.loading = false;
  507. });
  508. },
  509. getDateRangeYear(sDate, eDate) {
  510. let yearArr = [];
  511. if (sDate && eDate) {
  512. let sDateYear = moment(sDate).format('yyyy');
  513. let dDateYear = moment(eDate).format('yyyy');
  514. for (let i=sDateYear; i<=dDateYear; i++) {
  515. yearArr.push(i);
  516. }
  517. }
  518. return yearArr;
  519. },
  520. getDictList(code, toListKey) {
  521. getDictionary({ code }).then((res) => {
  522. this[toListKey] = res.data.data.map((item) => {
  523. return { label: item.dictValue, value: item.dictKey };
  524. });
  525. });
  526. },
  527. handleYearInput(e) {
  528. this.calcBudgetIsExceed(this.formData.xmysze);
  529. },
  530. /**
  531. * 计算是否超出预算
  532. * @param total 预算总额
  533. */
  534. calcBudgetIsExceed(total) {
  535. let yearTotal = 0;
  536. let projectBudget = Number(total || 0);
  537. this.yearList.forEach(year => {
  538. let num = Number(this.formData[year] || 0);
  539. yearTotal += num;
  540. });
  541. if (yearTotal > projectBudget) {
  542. this.budgetIsExceed = true;
  543. } else {
  544. this.budgetIsExceed = false;
  545. }
  546. },
  547. validForm() {
  548. let errorText = '';
  549. if (!this.formData.xmmc) {
  550. errorText = '请输入项目名称';
  551. } else if (/技改|技术改造|推广|打样|翻新|产业化|生产线|改造|年产|示范/g.test(this.formData.xmmc)) {
  552. errorText = '研发项目名称,不符合统计部门的命名要求';
  553. } else if (!this.formData.xmbh) {
  554. errorText = '请输入项目编号';
  555. } else if (!this.formData.xmsqdwid || !this.formData.xmsqdwid.length) {
  556. errorText = '请选择项目申请单位';
  557. } else if (!this.formData.xmkssj) {
  558. errorText = '请选择项目开始时间';
  559. } else if (!this.formData.xmjssj) {
  560. errorText = '请选择项目结束时间';
  561. } else if (!this.formData.yjlx) {
  562. errorText = '请选择研究类型'
  563. } else if (!this.formData.xmfzr) {
  564. errorText = '请选择项目负责人';
  565. } else if (!this.formData.xmly) {
  566. errorText = '请选择项目来源';
  567. } else if (!this.formData.xmkzxs) {
  568. errorText = '请选择项目开展形式';
  569. } else if (!this.formData.yqcgxs) {
  570. errorText = '请选择预期成果形式';
  571. } else if (!this.formData.xmjsjjmb) {
  572. errorText = '请选择项目技术经济目标';
  573. }
  574. else {
  575. this.yearList.forEach(year => {
  576. if (this.formData[year] === null || this.formData[year] === undefined || this.formData[year] === '') {
  577. errorText = `${year}年的预算不能为空`;
  578. }
  579. });
  580. }
  581. return errorText;
  582. },
  583. handleResetBtn() {
  584. this.yearList.forEach(year => {
  585. this.formData[year] = '';
  586. });
  587. this.formData = {
  588. xmmc: '',
  589. xmbh: '',
  590. xmkssj: '',
  591. xmjssj: '',
  592. xmsqdwid: [],
  593. xmfzr: '',
  594. yjlx: '',
  595. xmly: '',
  596. xmkzxs: '',
  597. yqcgxs: [],
  598. xmjsjjmb: [],
  599. lxpw: [],
  600. lxbg: [],
  601. qtzl: []
  602. };
  603. this.yearList = [];
  604. this.$refs.secondUnitCascader.cascaderVal = [];
  605. },
  606. handleSaveBtn(status) {
  607. if (!this.operateType || this.operateType === 'add' || this.formData.status == 0) {
  608. let errorText = this.validForm();
  609. if (errorText) {
  610. this.$message.error(errorText+'!');
  611. return;
  612. }
  613. let params = deepClone(this.formData);
  614. params.yqcgxs = params.yqcgxs ? params.yqcgxs.join(',') : '';
  615. params.xmjsjjmb = params.xmjsjjmb ? params.xmjsjjmb.join(',') : '';
  616. params.xmsqdwid = params.xmsqdwid ? params.xmsqdwid[params.xmsqdwid.length - 1] : '';
  617. params.lxbg = JSON.stringify(params.lxbg);
  618. params.lxpw = JSON.stringify(params.lxpw);
  619. params.qtzl = JSON.stringify(params.qtzl);
  620. let yearAmountList = [];
  621. this.yearList.forEach(year => {
  622. yearAmountList.push({ year: Number(year), amount: params[year] || 0 });
  623. delete params[year];
  624. });
  625. params.xmyszemx = JSON.stringify(yearAmountList);
  626. params.xmysze = this.getXmysze;
  627. params.status = status;
  628. this.saveData(params);
  629. } else if (this.operateType === 'edit') {
  630. let errorText = this.validForm();
  631. if (errorText) {
  632. this.$message.error(errorText+'!');
  633. return;
  634. }
  635. let params = {
  636. xmId: this.formData.id,
  637. yjlx: this.formData.yjlx,
  638. xmly: this.formData.xmly,
  639. xmkzxs: this.formData.xmkzxs,
  640. yqcgxs: this.formData.yqcgxs.join(','),
  641. xmjsjjmb: this.formData.xmjsjjmb.join(',')
  642. };
  643. params.lxbg = JSON.stringify(this.formData.lxbg);
  644. params.lxpw = JSON.stringify(this.formData.lxpw);
  645. params.qtzl = JSON.stringify(this.formData.qtzl);
  646. this.addOrUpdate(params);
  647. }
  648. },
  649. saveData(params) {
  650. this.loading = true;
  651. save(params).then(({ data }) => {
  652. this.loading = false;
  653. if (data.code == 200) {
  654. this.handleResetBtn();
  655. this.$emit('success', data.data);
  656. this.$message.success(params.status == 0 ? '保存成功' : '立项成功');
  657. }
  658. }).catch(err => {
  659. this.loading = false;
  660. });
  661. },
  662. addOrUpdate(params) {
  663. // let func = this.operateType === 'edit' ? update : add;
  664. this.loading = true;
  665. update(params).then(({ data }) => {
  666. this.loading = false;
  667. if (data.code == 200) {
  668. this.handleResetBtn();
  669. this.$emit('success', data.data);
  670. this.$message.success(this.operateType === 'edit' ? '修改成功!' : '保存成功!');
  671. }
  672. }).catch(err => {
  673. this.loading = false;
  674. });
  675. },
  676. handleExportWord() {
  677. exportBlob(
  678. `/api/kd-scientific/xm/approval/export?${
  679. this.website.tokenHeader
  680. }=${getToken()}`,
  681. { xmId: this.projectId }
  682. ).then((res) => {
  683. downloadXls(
  684. res.data,
  685. `${this.formData.xmmc}项目立项表.doc`
  686. );
  687. });
  688. },
  689. },
  690. };
  691. </script>
  692. <style lang="scss" scoped>
  693. .page-title {
  694. text-align: center;
  695. font-size: 24px;
  696. }
  697. .project-basic-info .info-row {
  698. line-height: 26px;
  699. color: #333;
  700. }
  701. .apply-form {
  702. width: 800px;
  703. margin: 30px auto;
  704. }
  705. table {
  706. width: 100%;
  707. border: 1px solid #333;
  708. }
  709. .doc-label {
  710. width: 100px;
  711. text-align: center;
  712. padding: 6px;
  713. color: #777;
  714. font-size: 14px;
  715. }
  716. .doc-input {
  717. width: 300px;
  718. text-align: center;
  719. color: #333;
  720. }
  721. .el-input__inner {
  722. border: none;
  723. }
  724. tr td {
  725. border: 1px solid #333;
  726. }
  727. .year-list {
  728. &-item {
  729. display: flex;
  730. height: 32px;
  731. line-height: 32px;
  732. border-bottom: 1px solid #333;
  733. &:last-child {
  734. border-bottom: 0;
  735. }
  736. .year {
  737. width: 65px;
  738. border-right: 1px solid #333;
  739. }
  740. .year-input {
  741. input {
  742. width: 100%;
  743. min-height: 30px;
  744. border: 0;
  745. }
  746. }
  747. }
  748. }
  749. .red {
  750. color: red;
  751. }
  752. .tip {
  753. position: relative;
  754. top: 0;
  755. color: red;
  756. padding-left: 90px;
  757. margin-top: 0;
  758. font-size: 12px;
  759. }
  760. </style>