Task.vue 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. <template>
  2. <div class="create-container" v-loading="loading">
  3. <div class="title h1" v-if="!isModifyMode">任务</div>
  4. <div class="create-body">
  5. <div class="title h2" v-if="!isModifyMode">基本信息</div>
  6. <el-row :gutter="20">
  7. <el-col :span="15">
  8. <el-form :model="task" :rules="rules" ref="task" label-width="120px" class="demo-task"
  9. style="margin:0 0 0 80px;">
  10. <el-form-item label="任务名称" prop="title" style="width: 700px;">
  11. <el-input size="small" v-if="isModifyMode" v-model="task.title"></el-input>
  12. <span v-if="!isModifyMode">{{ task.title }}</span>
  13. <el-tag v-if="!isModifyMode" :type="task.statusVO&&task.statusVO.style">{{
  14. task.statusVO ?
  15. task.statusVO.text : ''
  16. }}
  17. </el-tag>
  18. </el-form-item>
  19. <el-form-item label="任务描述" prop="description" style="width: 700px;">
  20. <el-input autosize v-if="isModifyMode" type="textarea" v-model="task.description"></el-input>
  21. <span v-if="!isModifyMode">{{ task.description ? task.description : '暂无' }}</span>
  22. </el-form-item>
  23. <el-form-item label="任务报价" prop="quotePrice" style="width: 700px;">
  24. <el-input size="small" type="number" v-if="isModifyMode" v-model="task.quotePrice">
  25. <template slot="append">¥</template>
  26. </el-input>
  27. <span v-if="!isModifyMode">¥{{ task.quotePrice }}</span>
  28. </el-form-item>
  29. <!--<el-form-item type="number" label="任务定价" prop="fixedPrice">-->
  30. <!--<el-input v-if="isModifyMode" v-model="task.fixedPrice">-->
  31. <!--<template slot="append">¥</template>-->
  32. <!--</el-input>-->
  33. <!--<span v-if="!isModifyMode">{{task.fixedPrice}}</span>-->
  34. <!--</el-form-item>-->
  35. <el-form-item label="测试类型" prop="serviceType">
  36. <el-radio-group v-if="isModifyMode" v-model="task.serviceType" @change="handleTestTypeChange">
  37. <span v-for="(item,index) in serviceType" :key="index">
  38. <el-radio :label="item.code" name="serviceType">{{ item.name }}</el-radio>
  39. </span>
  40. </el-radio-group>
  41. <span class="badge" v-if="!isModifyMode">{{ serviceName }}</span>
  42. </el-form-item>
  43. <el-form-item label="服务序列号" prop="endPoint" style="width: 700px;"
  44. v-if="showBD&&task.endPoint&&currType.type===1"
  45. >
  46. <el-input v-if="isModifyMode" v-model="task.endPoint.serverCode" label="examId"></el-input>
  47. <span v-if="!isModifyMode&&showBD">{{ task.endPoint.serverCode }}</span>
  48. </el-form-item>
  49. <el-form-item label="任务可见性" prop="resource" style="width: 700px;">
  50. <div v-if="!isModifyMode">
  51. <!--<div v-if="task.resource=='1'">{{updateLocation(task.location)}}</div>-->
  52. <div v-if="task.resource==0">定向</div>
  53. <div v-if="task.resource==2">{{ resourceType[task.resource] }}</div>
  54. </div>
  55. <el-tabs
  56. :tab-position="tabPosition"
  57. v-model="task.resource"
  58. style="max-height: 200px;"
  59. v-if="isModifyMode"
  60. >
  61. <el-tab-pane :label="resourceType[0]" name="0">
  62. <el-radio-group v-model="task.institution" @change="handleTestTypeChange">
  63. <el-radio
  64. :label="item"
  65. name="type"
  66. v-for="(item,index) in institutionArray"
  67. :key="index"
  68. >{{ item.name }}
  69. </el-radio>
  70. </el-radio-group>
  71. </el-tab-pane>
  72. <!--<el-tab-pane :label="resourceType[1]" name="1">-->
  73. <!--<provincecity-->
  74. <!--ref="addFormProvince"-->
  75. <!--@selectChange="locationChange"-->
  76. <!--:provinceCode="task.location == null ||task.location.provinceCode==null?'3200':task.location.provinceCode"-->
  77. <!--:cityCode="task.location == null ||task.location.cityCode==null?'3201':task.location.cityCode"-->
  78. <!--&gt;</provincecity>-->
  79. <!--</el-tab-pane>-->
  80. <el-tab-pane :label="resourceType[2]" name="2"></el-tab-pane>
  81. </el-tabs>
  82. </el-form-item>
  83. <el-form-item v-if="!isModifyMode && task.resource==0 && showBD" label="接包人员/机构" prop="agencyName" style="width: 700px;">
  84. <span>{{task.agencyName}}</span>
  85. </el-form-item>
  86. <el-form-item label="领取人数" prop="contactPhone" v-if="isModifyMode&&task.resource !== '0' && currType.type===0">
  87. <el-input-number v-model="task.participantCount" :min="1" :max="1000" label="领取人数"></el-input-number>
  88. </el-form-item>
  89. <el-form-item label="领取人数" prop="contactPhone"
  90. v-if="isModifyMode&&task.resource !== '0' && currType.type===1">
  91. <el-input-number v-model="task.participantCount" :min="2" :max="1000" label="领取人数"></el-input-number>
  92. </el-form-item>
  93. <el-form-item label="领取人数" prop="quotePrice" v-if="!isModifyMode">
  94. {{ task.acceptedCount }}/{{ task.participantCount }}
  95. </el-form-item>
  96. <el-form-item label="需求文档" prop="doc">
  97. <el-upload
  98. style="width: 400px"
  99. v-if="isModifyMode"
  100. drag
  101. class="upload-demo"
  102. action=""
  103. :on-remove="handleRemove"
  104. :before-remove="beforeRemove"
  105. :limit="1"
  106. :on-exceed="handleExceed"
  107. :http-request="uploadRequireDoc"
  108. :file-list="task.doc"
  109. >
  110. <i class="el-icon-upload"></i>
  111. <div class="el-upload__text">
  112. 将文件拖到此处,或
  113. <em>点击上传</em>
  114. </div>
  115. </el-upload>
  116. <span>
  117. <span v-if="task.requireDocUrl == null || task.requireDocUrl == ''">
  118. <i class="el-icon-document"></i>暂无文件
  119. </span>
  120. <span v-if="task.requireDocUrl != null && task.requireDocUrl != ''">
  121. <a :href="task.requireDocUrl"><el-link :underline="false" type="primary"><i
  122. class="el-icon-document"></i>下载文档</el-link></a>
  123. </span>
  124. </span>
  125. </el-form-item>
  126. <el-form-item v-if="!isModifyMode && task.resource==0 && showBD" label="任务接收码" prop="agencyName" style="width: 700px;">
  127. <span>{{task.acceptedPassword}}</span>
  128. </el-form-item>
  129. <el-form-item label="任务截止时间" prop="datetime">
  130. <div class="block" v-if="isModifyMode">
  131. <el-date-picker
  132. size="small"
  133. v-model="task.datetime"
  134. type="datetime"
  135. placeholder="选择截止时间"
  136. align="right"
  137. :picker-options="pickerOptions"
  138. ></el-date-picker>
  139. </div>
  140. <span v-if="!isModifyMode">{{ dateFormat(new Date(task.datetime), 'yyyy-MM-dd HH:mm:ss') }}</span>
  141. </el-form-item>
  142. <el-form-item v-if="isModifyMode">
  143. <div class="btn btn-small btn-info" @click="updateTask()">确认修改</div>
  144. <!--<div class="btn btn-small" @click="resetForm()">重置</div>-->
  145. <div class="btn btn-small" @click="cancelMode()">取消</div>
  146. </el-form-item>
  147. <el-form-item v-if="editShortLink && task.endPoint.serverCode && taskOperationControl.confirmFinish"
  148. label="任务面板链接" props="shortLink">
  149. <el-input v-model="shortLink" placeholder="请输入短链接生成任务报告" style="width: 800px">
  150. <template slot="append">
  151. <el-button @click="getTaskDataBoard()">确定</el-button>
  152. </template>
  153. </el-input>
  154. </el-form-item>
  155. <el-form-item v-if="shortLink && !editShortLink" label="任务面板链接" props="shortLink">
  156. {{ shortLink }}
  157. <i class="el-icon-edit" @click="editShortLink = true" v-if="taskOperationControl.confirmFinish"/>
  158. </el-form-item>
  159. <el-form-item v-if="!isModifyMode">
  160. <el-button size="mini" @click="toProject()">项目详情</el-button>
  161. <el-popover
  162. placement="top-start"
  163. title="确认结束?"
  164. width="200"
  165. trigger="hover"
  166. content="测评机构已提交结束申请,请确认是否结束该任务">
  167. <el-button v-if="taskOperationControl.confirmFinish" type="success" size="mini" slot="reference"
  168. @click="endTask()">确认结束
  169. </el-button>
  170. </el-popover>
  171. <el-popover
  172. placement="top-start"
  173. title="确认提交?"
  174. width="200"
  175. trigger="hover"
  176. content="提交任务后不可更改,等待区域管理员验收">
  177. <el-button v-if="taskOperationControl.finish" type="primary" size="mini" slot="reference"
  178. @click="submitTaskRequest()">提交任务
  179. </el-button>
  180. </el-popover>
  181. <el-popover
  182. placement="top-start"
  183. title="确认拒绝?"
  184. width="200"
  185. trigger="hover"
  186. content="拒绝后不可再接收此任务,且该任务对您不可见">
  187. <el-button v-if="taskOperationControl.reject" type="danger" size="mini" slot="reference"
  188. @click="rejectTask()">拒绝任务
  189. </el-button>
  190. </el-popover>
  191. <el-popover
  192. placement="top-start"
  193. title="确认接收?"
  194. width="200"
  195. trigger="hover"
  196. content="接收任务后请认真完成!">
  197. <el-button v-if="taskOperationControl.receive" type="primary" size="mini" slot="reference"
  198. @click="showTaskCodeModal = !showTaskCodeModal">接收任务
  199. </el-button>
  200. </el-popover>
  201. <el-button v-if="taskOperationControl.writeReport" type="primary" size="mini" @click="gotoWriteReport()">
  202. 填写报告
  203. </el-button>
  204. <el-button v-if="taskOperationControl.update" type="primary" size="mini" @click="modifyForm()">修改任务
  205. </el-button>
  206. <el-button v-if="featureTaskRecommend && taskOperationControl.taskRecommend" type="primary" size="mini"
  207. @click="recommendTask()">任务推荐
  208. </el-button>
  209. <!-- <el-button v-if="taskOperationControl.exportTask && task.exportUrl != null && task.exportUrl != ''" type="primary" size="mini">-->
  210. <!-- <a :href="task.exportUrl" style="color:white">导出任务</a>-->
  211. <!-- </el-button>-->
  212. <el-button v-if="taskOperationControl.exportTask" type="primary" size="mini" @click="toExportTask()">
  213. 导出任务
  214. </el-button>
  215. <el-button v-if="taskOperationControl.uploadReport" type="primary" size="mini" @click="toCreateReport()">
  216. 上传报告
  217. </el-button>
  218. <el-button v-if="taskOperationControl.taskDemonstrate" type="success" size="mini"
  219. @click="gotoDataboard()">
  220. 任务面板
  221. </el-button>
  222. <el-button v-if="taskOperationControl.forkTask" type="primary" size="mini"
  223. @click="showTaskForkModal = !showTaskForkModal">
  224. fork任务
  225. </el-button>
  226. <!--<div class="btn btn-small btn-info"-->
  227. <!--v-if="taskOperationControl.confirmFinish"-->
  228. <!--@click="endTask()">确认结束-->
  229. <!--</div>-->
  230. <!--<div class="btn btn-small btn-info" v-if="!taskOperationControl.finish" @click="submitTaskRequest()">提交任务-->
  231. <!--</div>-->
  232. <!--<div class="btn btn-small btn-info" v-if="!taskOperationControl.receive" @click="receiveTask()">接收任务</div>-->
  233. <!--<div class="btn btn-small btn-danger" v-if="!taskOperationControl.reject" @click="rejectTask()">拒绝任务</div>-->
  234. <!--<div class="btn btn-small btn-info" v-if="taskOperationControl.update" @click="modifyForm()">修改任务</div>-->
  235. <!--<div class="btn btn-small btn-info" v-if="!taskOperationControl.uploadReport" @click="toCreateReport()">上传报告-->
  236. <!--</div>-->
  237. </el-form-item>
  238. </el-form>
  239. </el-col>
  240. <el-col :span="9">
  241. <TaskCloud :info="wordCloud" v-if="wordCloud.length"></TaskCloud>
  242. </el-col>
  243. </el-row>
  244. </div>
  245. <div class="create-body" v-if="!isModifyMode">
  246. <div class="title h2">用户报告列表</div>
  247. <el-collapse accordion style="margin: 0 30px">
  248. <el-collapse-item v-for="(item,index) in acceptedUserList" :key="item.id">
  249. <template slot="title">
  250. <el-row style="width: 100%;font-size: 16px">
  251. <el-col :span="6">{{ item.userVO.userName }}</el-col>
  252. <el-col :span="6">{{ item.userVO.email }}</el-col>
  253. <el-col :span="6">
  254. <el-tag type="success" v-if="item.crowdReportVOS">已提交报告</el-tag>
  255. <el-tag type="info" v-if="!item.crowdReportVOS">未提交报告</el-tag>
  256. </el-col>
  257. <el-col :span="6">
  258. <el-tag type="success" v-if="item.isCommitted">已提交任务</el-tag>
  259. <el-tag type="info" v-if="!item.isCommitted">未提交任务</el-tag>
  260. </el-col>
  261. </el-row>
  262. </template>
  263. <report-list v-bind:reports="item.crowdReportVOS" v-bind:taskId="taskId" v-bind:projectId="projectId"/>
  264. </el-collapse-item>
  265. </el-collapse>
  266. <!-- <report-list v-if="isAgency" v-bind:reports="reportList" v-bind:taskId="taskId" v-bind:projectId="projectId"/>-->
  267. <!-- <report-list v-bind:reports="reportList" v-bind:taskId="taskId" v-bind:projectId="projectId"/>-->
  268. </div>
  269. <el-dialog title="请输入任务接收码" :visible.sync="showTaskCodeModal">
  270. <el-input v-model="taskValidCode" autocomplete="off" placeholder="请输入任务接收码"></el-input>
  271. <div slot="footer" class="dialog-footer">
  272. <el-button @click="showTaskCodeModal = false;taskValidCode = ''">取 消</el-button>
  273. <el-button type="primary" @click="handleTaskCodeValid()">确 定</el-button>
  274. </div>
  275. </el-dialog>
  276. <el-dialog title="Fork任务?" :visible.sync="showTaskForkModal">
  277. <div>确定基于该任务Fork新任务?</div>
  278. <div slot="footer" class="dialog-footer">
  279. <el-button @click="showTaskForkModal = false;">取 消</el-button>
  280. <el-button type="primary" @click="handleForkTask()">确 定</el-button>
  281. </div>
  282. </el-dialog>
  283. </div>
  284. </template>
  285. <script>
  286. import ResourceType from '@/constants/enum/resource-type.js'
  287. import provincecity from '@/components/commons/ProvinceCity'
  288. import ReportList from '@/components/report/ReportList'
  289. import TaskCloud from '@/components/task/TaskCloud'
  290. import Http from '@/js/http.js'
  291. import Apis from '@/js/api.js'
  292. import {CONFIG} from "../../config";
  293. import {notify} from '@/constants/index'
  294. import {
  295. ensureEndTask,
  296. exportTask,
  297. getAllAgencies,
  298. getAllAgencyAndTestUser,
  299. getAllServiceTypes,
  300. getFormalTimeFromDate,
  301. getProvinceCodeByProvinceName,
  302. getProvinceNameByProvinceCode,
  303. getTask,
  304. receiveTaskRequest,
  305. rejectTask,
  306. storageGet,
  307. submitTaskRequest,
  308. updateTask,
  309. getTaskWordCloud
  310. } from '@/js/index'
  311. import {AxiosInstance as axios} from "axios";
  312. export default {
  313. name: 'Task',
  314. components: {
  315. provincecity,
  316. ReportList,
  317. TaskCloud
  318. },
  319. data() {
  320. return {
  321. showTaskCodeModal: false,
  322. showTaskForkModal: false,
  323. taskValidCode:'',
  324. featureTaskRecommend: CONFIG.feature_task_recommend,
  325. taskRecommendUrl: CONFIG.task_recommend_url,
  326. currType: {},
  327. user: {},
  328. serviceName: '',
  329. showBD: true,
  330. rolesPermissions: {},
  331. loading: false,
  332. isModifyMode: false, institutionArray: [],
  333. tabPosition: 'top',
  334. resourceType: ResourceType,
  335. serviceType: [],
  336. taskId: '',
  337. projectId: '',
  338. taskOperationControl: {
  339. confirmFinish: false,
  340. finish: false,
  341. receive: false,
  342. update: false,
  343. uploadReport: false,
  344. writeReport: false,
  345. taskDemonstrate: false,
  346. taskRecommend: false,
  347. exportTask: false,
  348. forkTask: false,
  349. },
  350. crowdReportUrl: '',
  351. exportTaskUrl: '',
  352. wordCloud: [],
  353. task: {
  354. agencyId: '',
  355. agencyName: '',
  356. acceptedPassword: '',
  357. status: '',
  358. name: '',
  359. desc: '',
  360. serviceType: '',
  361. resource: '',
  362. location: {},
  363. institution: {},
  364. datetime: '',
  365. quotePrice: '',
  366. fixedPrice: '',
  367. doc: [],
  368. requireDocUrl: '',
  369. participantCount: 1,
  370. exportUrl: '',
  371. title: '',
  372. description: '',
  373. endPoint: {
  374. serverCode: '',
  375. token: ''
  376. }
  377. },
  378. reportList: [],
  379. pickerOptions: {
  380. shortcuts: [
  381. {
  382. text: '今天',
  383. onClick(picker) {
  384. picker.$emit('pick', new Date())
  385. }
  386. },
  387. {
  388. text: '昨天',
  389. onClick(picker) {
  390. const date = new Date()
  391. date.setTime(date.getTime() - 3600 * 1000 * 24)
  392. picker.$emit('pick', date)
  393. }
  394. },
  395. {
  396. text: '一周前',
  397. onClick(picker) {
  398. const date = new Date()
  399. date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
  400. picker.$emit('pick', date)
  401. }
  402. }
  403. ]
  404. },
  405. rules: {
  406. title: [
  407. {required: true, message: '请输入任务名称', trigger: 'blur'},
  408. {min: 5, max: 50, message: '任务名称长度在 5 到 50 个字符', trigger: 'blur'}
  409. ],
  410. serviceType: [
  411. {required: true, message: '测试类型不可为空', trigger: 'change'},
  412. ],
  413. description: [{required: true, message: '请填写描述', trigger: 'blur'}],
  414. //price: [{required: true, message: '请填写价格', trigger: 'blur'}],
  415. quotePrice: [
  416. {required: true, message: '预算不可为空', trigger: 'blur'},
  417. {
  418. validator: (rule, value, callback) => {
  419. if (value < 0) {
  420. callback(new Error('请输入不小于0的数'))
  421. } else {
  422. callback()
  423. }
  424. }, trigger: 'blur'
  425. },
  426. ],
  427. resource: [
  428. {required: true},
  429. {
  430. validator: (rule, value, callback) => {
  431. if (value == 0 && this.task.institution.id == null) {
  432. callback(new Error('定向发布至少要选择一个测评机构'))
  433. } else {
  434. callback()
  435. }
  436. }, trigger: 'change'
  437. },
  438. ],
  439. endPoint: [
  440. {
  441. validator: (rule, value, callback) => {
  442. if (this.currType.type === 1 && this.task.endPoint.serverCode === '') {
  443. callback(new Error('请填写对应得服务序列号'))
  444. } else {
  445. callback()
  446. }
  447. }, trigger: ['change', 'blur']
  448. },
  449. ],
  450. datetime: [{required: true, message: '截止时间不可为空', trigger: 'blur'}],
  451. },
  452. acceptedUserList: [],
  453. shortLink: '',
  454. editShortLink: false,
  455. }
  456. },
  457. watch: {
  458. institutionArray(val) {
  459. this.institutionArray = val
  460. },
  461. serviceType(val) {
  462. this.serviceType = val
  463. },
  464. deep: true
  465. },
  466. mounted() {
  467. this.$nextTick(() => {
  468. this.init()
  469. })
  470. },
  471. methods: {
  472. handleTaskCodeValid(){
  473. let str1 = this.projectId;
  474. let str2 = this.task.code;
  475. let str = str1.substring(str1.length-2) + str2.substring(str2.length-2);
  476. if(str === this.taskValidCode){
  477. //接收码正确,可以正确接收任务
  478. this.receiveTask();
  479. this.showTaskCodeModal = false;
  480. }else{
  481. // 提示接收码错误
  482. notify('error', '接收码错误')
  483. }
  484. },
  485. handleForkTask(){
  486. //跳转到taskFork
  487. this.$router.push({
  488. name: 'TaskCreate',
  489. params: this.task
  490. })
  491. this.showTaskForkModal = false;
  492. },
  493. //跳转到任务对应的数据面板
  494. gotoDataboard() {
  495. window.open(this.task.endPoint.token)
  496. },
  497. //根据短链接获取生成databoard
  498. getTaskDataBoard() {
  499. this.showLoading()
  500. Http.put(`/api/project/${this.projectId}/task/${this.taskId}/addToken`, {"token": this.shortLink}).then((res) => {
  501. this.taskOperationControl = res.taskOperationControl;
  502. this.task.endPoint = res.crowdTaskVO.endPointVO;
  503. this.shortLink = res.crowdTaskVO.endPointVO.token;
  504. if (this.shortLink != '') {
  505. this.editShortLink = false;
  506. }
  507. this.hideLoading()
  508. })
  509. },
  510. getServiceByCode(code) {
  511. let serviceName = this.serviceType.filter((item) => {
  512. return item.code === code;
  513. });
  514. return serviceName && serviceName[0] && serviceName[0]['name']
  515. },
  516. handleTestTypeChange(val) {
  517. let type = this.serviceType.filter((item) => {
  518. return item.code === val;
  519. });
  520. this.currType = type[0] ? type[0] : {};
  521. if (this.currType.type === 0) {
  522. this.$refs.task.clearValidate('endPoint');
  523. }
  524. },
  525. init() {
  526. this.taskId = this.$route.params.taskId
  527. this.projectId = this.$route.params.projectId
  528. this.setUserInfo()
  529. this.setServiceType()
  530. //this.loadData(this.projectId, this.taskId)
  531. this.getTaskDetail()
  532. this.getWordCloud()
  533. // this.setInstitutions()
  534. },
  535. //北斗测试报告填写跳转
  536. gotoWriteReport() {
  537. window.open(this.crowdReportUrl, '_blank');
  538. },
  539. //跳转至项目详情页面
  540. toProject() {
  541. this.$router.push({
  542. name: 'Project',
  543. params: {projectId: this.projectId}
  544. })
  545. },
  546. //切换至可编辑页面
  547. modifyForm() {
  548. // this.task.serviceType = ''
  549. this.isModifyMode = true
  550. },
  551. //切换至不可编辑页面
  552. cancelMode() {
  553. this.isModifyMode = false
  554. },
  555. //重置表单
  556. resetForm() {
  557. this.task.name = ''
  558. this.task.desc = ''
  559. this.task.quotePrice = ''
  560. this.task.fixedPrice = ''
  561. this.task.type = ''
  562. this.task.resource = '2' //如果是广场不用管Location和institution ,定向看institution,区域看location
  563. this.task.location = {provinceCode: '', cityCode: ''}
  564. this.task.institution = ''
  565. this.task.datetime = ''
  566. this.task.participantCount = 1
  567. // this.task.endPointVO.caseId = ''
  568. // this.task.endPointVO.examId = ''
  569. },
  570. //显示页面加载画面
  571. showLoading() {
  572. this.loading = true
  573. },
  574. //隐藏页面加载画面
  575. hideLoading() {
  576. this.loading = false
  577. },
  578. //加载用户信息
  579. setUserInfo() {
  580. this.user = storageGet('user')
  581. this.rolesPermissions = storageGet('rolesPermissions')
  582. if (storageGet('rolesPermissions').isRegionManager || storageGet('rolesPermissions').isSystemAdministrator) {
  583. this.showBD = true;
  584. } else {
  585. this.showBD = false;
  586. }
  587. },
  588. //加载任务的测试类型
  589. setServiceType() {
  590. getAllServiceTypes().then((res) => {
  591. this.serviceType = res
  592. }).catch((error) => {
  593. notify('error', '加载测试类型失败')
  594. })
  595. },
  596. //加载所有的测评机构
  597. setInstitutions() {
  598. getAllAgencyAndTestUser().then((res) => {
  599. this.institutionArray = res
  600. }).catch((error) => {
  601. notify('error', '获取机构列表失败')
  602. })
  603. },
  604. //获取任务详情
  605. getTaskDetail() {
  606. this.showLoading()
  607. getTask(this.projectId, this.taskId, this.getTaskDetailSuccess, this.getTaskDetailFail)
  608. },
  609. //获取词云
  610. getWordCloud() {
  611. getTaskWordCloud(this.projectId, this.taskId, this.getTaskCloudSuccess, this.getTaskCloudFail)
  612. },
  613. getTaskCloudSuccess(words) {
  614. this.wordCloud = words.data;
  615. },
  616. getTaskCloudFail(err) {
  617. notify('error', err)
  618. },
  619. //获取任务详情成功时回调函数
  620. getTaskDetailSuccess(res) {
  621. this.hideLoading()
  622. // console.log(res)
  623. this.taskId = res.crowdTaskVO.id
  624. this.projectId = res.crowdTaskVO.projectId
  625. this.task.code = res.crowdTaskVO.code
  626. this.task.title = res.crowdTaskVO.title
  627. this.task.description = res.crowdTaskVO.description
  628. this.task.serviceType = res.crowdTaskVO.serviceType
  629. this.task.resource = res.crowdTaskVO.resource.toString()
  630. this.task.location = getProvinceCodeByProvinceName(res.crowdTaskVO.location.provinceCode, res.crowdTaskVO.location.cityCode)
  631. this.task.institution = res.crowdTaskVO.institution
  632. this.task.datetime = new Date(res.crowdTaskVO.datetime)
  633. this.task.quotePrice = res.crowdTaskVO.quotePrice
  634. this.task.agencyName = res.crowdTaskVO.agencyName
  635. this.task.acceptedPassword = res.crowdTaskVO.acceptedPassword
  636. this.task.acceptedCount = res.crowdTaskVO.acceptedCount
  637. this.task.participantCount = res.crowdTaskVO.participantCount
  638. this.task.fixedPrice = res.crowdTaskVO.fixedPrice
  639. this.task.doc = []
  640. this.task.requireDocUrl = res.crowdTaskVO.requirementFile
  641. this.task.agencyId = res.crowdTaskVO.agencyId
  642. this.task.exportUrl = res.crowdTaskVO.exportUrl
  643. this.task.status = res.crowdTaskVO.status
  644. this.task.statusVO = res.crowdTaskVO.statusVO
  645. this.task.endPoint = res.crowdTaskVO.endPointVO ? res.crowdTaskVO.endPointVO : {
  646. serverCode: '',
  647. }
  648. this.taskOperationControl = res.taskOperationControl;
  649. this.acceptedUserList = res.acceptedUserList;
  650. this.crowdReportUrl = res.crowdTaskVO.writeReportUrl;
  651. this.handleFormatReport(this.acceptedUserList);
  652. this.handleTestTypeChange(res.crowdTaskVO.serviceType);
  653. this.serviceName = this.getServiceByCode(res.crowdTaskVO.serviceType);
  654. if (res.crowdTaskVO.endPointVO) {
  655. if (res.crowdTaskVO.endPointVO.token) {
  656. this.shortLink = res.crowdTaskVO.endPointVO.token;
  657. this.editShortLink = false
  658. } else {
  659. this.editShortLink = true
  660. }
  661. }
  662. // console.log(res.crowdTaskVO.endPointVO.token)
  663. // console.log(this.editShortLink)
  664. // console.log(this.isModifyMode)
  665. },
  666. //获取任务详情失败时回调函数
  667. getTaskDetailFail(error) {
  668. this.hideLoading()
  669. // notify('error', '获取任务详情失败:' + error.data)
  670. },
  671. //处理显示报告
  672. handleFormatReport(acceptedUserList) {
  673. acceptedUserList.map((user) => {
  674. user.crowdReportVOS && user.crowdReportVOS.map((report) => {
  675. report.userName = user.userVO.userName;
  676. this.reportList.push(report);
  677. })
  678. })
  679. },
  680. dateFormat(date, format) {
  681. date = new Date(date)
  682. let o = {
  683. 'M+': date.getMonth() + 1, //month
  684. 'd+': date.getDate(), //day
  685. 'H+': date.getHours(), //hour+8小时
  686. 'm+': date.getMinutes(), //minute
  687. 's+': date.getSeconds(), //second
  688. 'q+': Math.floor((date.getMonth() + 3) / 3), //quarter
  689. 'S': date.getMilliseconds() //millisecond
  690. }
  691. if (/(y+)/.test(format)) {
  692. format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
  693. }
  694. for (let k in o)
  695. if (new RegExp('(' + k + ')').test(format))
  696. format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
  697. return format;
  698. },
  699. //更新任务信息
  700. updateTask() {
  701. this.$refs['task'].validate(valid => {
  702. if (valid) {
  703. this.showLoading()
  704. const newTask = {
  705. name: this.task.title,
  706. desc: this.task.description,
  707. type: this.task.serviceType,
  708. resource: this.task.resource,
  709. location: this.task.location == null ? {} : getProvinceNameByProvinceCode(this.task.location.provinceCode, this.task.location.cityCode),
  710. institution: this.task.institution ? this.task.institution.id : null,
  711. datetime: this.task.datetime,
  712. quotePrice: this.task.quotePrice,
  713. fixedPrice: this.task.fixedPrice,
  714. requirementFile: this.task.requireDocUrl,
  715. participantCount: this.task.participantCount,
  716. endPoint: this.task.endPoint
  717. }
  718. //console.log(newTask)
  719. updateTask(this.projectId, this.taskId, newTask, this.updateTaskSuccess, this.updateTaskFail)
  720. } else {
  721. notify('error', '表单填写有误!')
  722. return false
  723. }
  724. })
  725. },
  726. //更新任务信息成功时回调函数
  727. updateTaskSuccess(res) {
  728. this.cancelMode()
  729. this.taskId = res.crowdTaskVO.id
  730. this.projectId = res.crowdTaskVO.projectId
  731. this.task.projectId = res.crowdTaskVO.projectId
  732. this.task.title = res.crowdTaskVO.title
  733. this.task.description = res.crowdTaskVO.description
  734. this.task.serviceType = res.crowdTaskVO.serviceType
  735. this.task.resource = res.crowdTaskVO.resource.toString()
  736. this.task.location = res.crowdTaskVO.location == null ? {
  737. provinceCode: 3200,
  738. cityCode: 3201
  739. } : getProvinceCodeByProvinceName(res.crowdTaskVO.location.provinceCode, res.crowdTaskVO.location.cityCode)
  740. this.task.institution = res.crowdTaskVO.institution
  741. this.task.datetime = new Date(res.crowdTaskVO.datetime)
  742. this.task.quotePrice = res.crowdTaskVO.quotePrice
  743. this.task.fixedPrice = res.crowdTaskVO.fixedPrice
  744. // this.task.endPointVO = res.crowdTaskVO.endPointVO
  745. this.task.doc = []
  746. this.task.requireDocUrl = res.crowdTaskVO.requirementFile,
  747. this.task.participantCount = res.crowdTaskVO.participantCount
  748. this.task.endPoint = res.crowdTaskVO.endPointVO ? res.crowdTaskVO.endPointVO : {
  749. serverCode: '',
  750. }
  751. this.task.createTime = res.crowdTaskVO.createTime,
  752. this.reportList = res.crowdReportVOList
  753. this.crowdReportUrl = res.crowdTaskVO.writeReportUrl;
  754. this.acceptedUserList = res.acceptedUserList
  755. this.handleTestTypeChange(res.crowdTaskVO.serviceType);
  756. this.serviceName = this.getServiceByCode(res.crowdTaskVO.serviceType)
  757. this.getWordCloud()
  758. this.hideLoading()
  759. notify('success', '修改成功')
  760. },
  761. //更新任务信息失败时回调函数
  762. updateTaskFail(error) {
  763. notify('error', '修改失败:' + error.data)
  764. this.hideLoading()
  765. },
  766. //上传任务需求文档
  767. uploadRequireDoc(param) {
  768. const formData = new FormData()
  769. let config = {
  770. //添加请求头
  771. headers: {'Content-Type': 'multipart/form-data'},
  772. }
  773. formData.append('file', param.file)
  774. Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
  775. notify('success', '上传成功')
  776. this.uploadRequireDocSuccess(res)
  777. }).catch((error) => {
  778. notify('error', '上传失败:' + error.data)
  779. this.uploadRequireDocFail(error)
  780. })
  781. },
  782. //上传任务需求文档成功时回调函数
  783. uploadRequireDocSuccess(res) {
  784. this.hideLoading()
  785. console.log('上传成功')
  786. this.task.requireDocUrl = res.data
  787. console.log(res.data)
  788. },
  789. //上传任务需求文档失败时回调函数
  790. uploadRequireDocFail(error) {
  791. this.hideLoading()
  792. notify('error', '任务需求文档上传失败:' + error.data)
  793. },
  794. //文档上传前响应函数
  795. //移除文档前的响应函数
  796. beforeRemove(file, fileList) {
  797. //return this.$confirm(`确定移除 ${file.name}?`)
  798. },
  799. //移除文档时的响应函数
  800. handleRemove(file, fileList) {
  801. console.log(file, fileList)
  802. },
  803. //需求文档添加进来时的响应函数
  804. handleExceed(files, fileList) {
  805. this.$message.warning(
  806. `当前限制选择 1 个文件,本次选择了 ${
  807. files.length
  808. } 个文件,共选择了 ${files.length + fileList.length} 个文件`
  809. )
  810. },
  811. //接收任务
  812. receiveTask() {
  813. this.$confirm('确认接收任务?', '提示', {
  814. confirmButtonText: '确认接收',
  815. cancelButtonText: '取消',
  816. type: 'success'
  817. }).then(() => {
  818. this.showLoading()
  819. receiveTaskRequest(this.projectId, this.taskId, this.user.userVO.id, this.receiveTaskSuccess, this.receiveTaskFail)
  820. }).catch(() => {
  821. })
  822. },
  823. //接收任务成功时的回调函数
  824. receiveTaskSuccess(res) {
  825. this.hideLoading()
  826. this.getTaskDetail();
  827. notify('success', '接收任务成功')
  828. // console.log(res)
  829. this.taskOperationControl = res.taskOperationControl
  830. this.task.status = res.crowdTaskVO.status
  831. this.task.institution = res.crowdTaskVO.institution
  832. },
  833. //接收任务失败时的回调函数
  834. receiveTaskFail(error) {
  835. this.hideLoading()
  836. notify('error', '接收任务失败:' + error.data)
  837. },
  838. // 任务推荐
  839. recommendTask() {
  840. let task = {
  841. "title": this.task.title,
  842. "description": this.task.description,
  843. "participantCount": this.task.participantCount,
  844. "quotePrice": this.task.quotePrice,
  845. "requirementFile": this.task.requireDocUrl,
  846. "serviceType": this.task.serviceType,
  847. "createTime": this.task.createTime,
  848. "datetime": this.task.datetime
  849. };
  850. Http.post('/recommendationtest/query', task).then((res) => {
  851. window.open(this.taskRecommendUrl, "_blank");
  852. })
  853. },
  854. //拒绝任务
  855. rejectTask() {
  856. this.$confirm('确认拒绝任务?拒绝后将不能再接收该任务', '提示', {
  857. confirmButtonText: '确认拒绝',
  858. cancelButtonText: '取消',
  859. type: 'success'
  860. }).then(() => {
  861. this.showLoading()
  862. rejectTask(this.projectId, this.taskId, this.rejectTaskSuccess, this.rejectTaskFail)
  863. }).catch(() => {
  864. })
  865. },
  866. //拒绝任务成功时的回调函数
  867. rejectTaskSuccess(res) {
  868. this.hideLoading()
  869. this.$router.push({
  870. name: 'Mine'
  871. })
  872. notify('success', '拒绝任务成功,已为您自动跳转到个人中心')
  873. },
  874. //拒绝任务失败时的回调函数
  875. rejectTaskFail(error) {
  876. this.hideLoading()
  877. notify('error', '拒绝任务失败:' + error.data)
  878. },
  879. //提交结束任务申请
  880. submitTaskRequest() {
  881. this.$confirm('确认提交任务?提交后将不能再修改', '提示', {
  882. confirmButtonText: '确认提交',
  883. cancelButtonText: '取消',
  884. type: 'success'
  885. }).then(() => {
  886. this.showLoading()
  887. submitTaskRequest(this.projectId, this.taskId, this.submitTaskRequestSuccess, this.submitTaskRequestFail)
  888. }).catch(() => {
  889. })
  890. },
  891. //提交结束任务申请成功时的回调函数
  892. submitTaskRequestSuccess(res) {
  893. this.hideLoading()
  894. console.log(res)
  895. this.taskOperationControl = res.taskOperationControl
  896. this.task.status = res.crowdTaskVO.status
  897. this.task.institution = res.crowdTaskVO.institution
  898. notify('success', '提交任务成功,等待区域管理员审核')
  899. this.getTaskDetail();
  900. },
  901. //提交结束任务申请失败时的回调函数
  902. submitTaskRequestFail(error) {
  903. this.hideLoading()
  904. notify('error', '提交任务失败:' + error.data)
  905. },
  906. //结束任务
  907. endTask() {
  908. this.$confirm('确认结束任务?', '提示', {
  909. confirmButtonText: '确认结束',
  910. cancelButtonText: '取消',
  911. type: 'success'
  912. }).then(() => {
  913. this.getTaskDetail()
  914. this.showLoading()
  915. ensureEndTask(this.projectId, this.taskId, this.endTaskSuccess, this.endTaskFail)
  916. }).catch(() => {
  917. })
  918. },
  919. //结束任务成功时的回调函数
  920. endTaskSuccess(res) {
  921. this.hideLoading()
  922. this.taskOperationControl = res.taskOperationControl
  923. this.task.status = res.crowdTaskVO.status
  924. this.task.institution = res.crowdTaskVO.institution
  925. notify('success', '结束任务成功!')
  926. this.getTaskDetail();
  927. },
  928. //结束任务失败时的回调函数
  929. endTaskFail(error) {
  930. this.hideLoading()
  931. notify('error', '结束任务失败:' + error.data)
  932. },
  933. // 导出任务
  934. toExportTask() {
  935. exportTask(this.projectId, this.taskId, this.exportTaskSuccess, this.exportTaskFail);
  936. },
  937. // 导出任务成功时的回调函数
  938. exportTaskSuccess(res) {
  939. this.hideLoading()
  940. console.log(res.data)
  941. this.exportTaskUrl = res.data;
  942. window.open(this.exportTaskUrl, "_self");
  943. notify('success', '任务导出成功!')
  944. },
  945. // 导出任务失败时的回调函数
  946. exportTaskFail(error) {
  947. this.hideLoading()
  948. notify('error', '导出任务失败:' + error.data)
  949. },
  950. //跳转到创建项目报告页面
  951. toCreateReport() {
  952. this.$router.push({
  953. name: 'TaskReportCreate',
  954. params: {
  955. scope: 1,
  956. dependencyCode: this.taskId,
  957. projectId: this.projectId,
  958. taskId: this.taskId,
  959. }
  960. })
  961. },
  962. reformDate(date) {
  963. return getFormalTimeFromDate(date)
  964. }
  965. },
  966. }
  967. //回收站
  968. //
  969. // updateLocation (location) {
  970. // console.log(location)
  971. // const loactionName = getProvinceNameByProvinceCode(location.provinceCode, location.cityCode)
  972. // // var provinceName = ''
  973. // // var cityName = ''
  974. // // for (var item of provinceCityJSON.provinces) {
  975. // // if (item.code === location.provinceCode) {
  976. // // provinceName = item.name
  977. // // for (var city of item.cities) {
  978. // // if (city.code === location.cityCode) {
  979. // // cityName = city.name
  980. // // break
  981. // // }
  982. // // }
  983. // // }
  984. // // }
  985. // return loactionName.provinceCode + ' / ' + loactionName.cityCode
  986. // },
  987. //
  988. // locationChange (provinceId, cityId) {
  989. // if (provinceId || cityId) {
  990. // this.task.location = {provinceCode: provinceId, cityCode: cityId}
  991. // }
  992. // },
  993. // submitForm (formName) {
  994. // this.$refs[formName].validate(valid => {
  995. // if (valid) {
  996. // this.isModifyMode = false
  997. //
  998. // } else {
  999. // console.log('error submit!!')
  1000. // return false
  1001. // }
  1002. // })
  1003. // },
  1004. </script>
  1005. <style lang="less" scoped>
  1006. .el-radio {
  1007. margin: 10px 20px 10px 0;
  1008. }
  1009. .el-form-item /deep/ .el-tabs__content {
  1010. /*max-height: 120px !important;*/
  1011. overflow: auto;
  1012. }
  1013. .el-collapse-item__content {
  1014. padding-bottom: 0 !important;
  1015. }
  1016. </style>